properly wrap pointer offsets at pointer size

This commit is contained in:
Ralf Jung 2017-06-05 18:07:26 -07:00
parent 7bfda59fe2
commit 684de68d6c
6 changed files with 40 additions and 36 deletions

View file

@ -391,7 +391,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// FIXME(solson) // FIXME(solson)
let dest_ptr = self.force_allocation(dest)?.to_ptr(); let dest_ptr = self.force_allocation(dest)?.to_ptr();
let discr_dest = dest_ptr.offset(discr_offset)?; let discr_dest = dest_ptr.offset(discr_offset, self.memory.layout)?;
self.memory.write_uint(discr_dest, discr_val, discr_size)?; self.memory.write_uint(discr_dest, discr_val, discr_size)?;
let dest = Lvalue::Ptr { let dest = Lvalue::Ptr {
@ -550,7 +550,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// FIXME(solson) // FIXME(solson)
let dest = self.force_allocation(dest)?.to_ptr(); let dest = self.force_allocation(dest)?.to_ptr();
let dest = dest.offset(offset.bytes())?; let dest = dest.offset(offset.bytes(), self.memory.layout)?;
let dest_size = self.type_size(ty)? let dest_size = self.type_size(ty)?
.expect("bad StructWrappedNullablePointer discrfield"); .expect("bad StructWrappedNullablePointer discrfield");
self.memory.write_int(dest, 0, dest_size)?; self.memory.write_int(dest, 0, dest_size)?;
@ -610,7 +610,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let dest = self.force_allocation(dest)?.to_ptr(); let dest = self.force_allocation(dest)?.to_ptr();
for i in 0..length { for i in 0..length {
let elem_dest = dest.offset(i * elem_size)?; let elem_dest = dest.offset(i * elem_size, self.memory.layout)?;
self.write_value_to_ptr(value, elem_dest, elem_ty)?; self.write_value_to_ptr(value, elem_dest, elem_ty)?;
} }
} }
@ -854,7 +854,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// FIXME: assuming here that type size is < i64::max_value() // 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 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; let offset = offset.overflowing_mul(pointee_size).0;
Ok(ptr.wrapping_signed_offset(offset)) Ok(ptr.wrapping_signed_offset(offset, self.memory.layout))
} }
pub(super) fn pointer_offset(&self, ptr: Pointer, pointee_ty: Ty<'tcx>, offset: i64) -> EvalResult<'tcx, Pointer> { pub(super) fn pointer_offset(&self, ptr: Pointer, pointee_ty: Ty<'tcx>, offset: i64) -> EvalResult<'tcx, Pointer> {
@ -865,7 +865,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
// FIXME: assuming here that type size is < i64::max_value() // 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 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) { return if let Some(offset) = offset.checked_mul(pointee_size) {
let ptr = ptr.signed_offset(offset)?; let ptr = ptr.signed_offset(offset, self.memory.layout)?;
self.memory.check_bounds(ptr, false)?; self.memory.check_bounds(ptr, false)?;
Ok(ptr) Ok(ptr)
} else { } else {
@ -1124,8 +1124,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let field_1_ty = self.get_field_ty(ty, 1)?; 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_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"); 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)?, a, field_0_size)?; self.memory.write_primval(ptr.offset(field_0, self.memory.layout)?, a, field_0_size)?;
self.memory.write_primval(ptr.offset(field_1)?, b, field_1_size)?; self.memory.write_primval(ptr.offset(field_1, self.memory.layout)?, b, field_1_size)?;
Ok(()) Ok(())
} }
@ -1242,7 +1242,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Ok(Value::ByVal(PrimVal::Ptr(p))) Ok(Value::ByVal(PrimVal::Ptr(p)))
} else { } else {
trace!("reading fat pointer extra of type {}", pointee_ty); trace!("reading fat pointer extra of type {}", pointee_ty);
let extra = ptr.offset(self.memory.pointer_size())?; let extra = ptr.offset(self.memory.pointer_size(), self.memory.layout)?;
let extra = match self.tcx.struct_tail(pointee_ty).sty { let extra = match self.tcx.struct_tail(pointee_ty).sty {
ty::TyDynamic(..) => PrimVal::Ptr(self.memory.read_ptr(extra)?), ty::TyDynamic(..) => PrimVal::Ptr(self.memory.read_ptr(extra)?),
ty::TySlice(..) | ty::TySlice(..) |
@ -1427,8 +1427,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
} }
let src_field_offset = self.get_field_offset(src_ty, i)?.bytes(); 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 dst_field_offset = self.get_field_offset(dest_ty, i)?.bytes();
let src_f_ptr = src_ptr.offset(src_field_offset)?; let src_f_ptr = src_ptr.offset(src_field_offset, self.memory.layout)?;
let dst_f_ptr = dest.offset(dst_field_offset)?; let dst_f_ptr = dest.offset(dst_field_offset, self.memory.layout)?;
if src_fty == dst_fty { if src_fty == dst_fty {
self.copy(src_f_ptr, dst_f_ptr, src_fty)?; self.copy(src_f_ptr, dst_f_ptr, src_fty)?;
} else { } else {

View file

@ -270,7 +270,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
_ => offset.bytes(), _ => offset.bytes(),
}; };
let ptr = base_ptr.offset(offset)?; let ptr = base_ptr.offset(offset, self.memory.layout)?;
let field_ty = self.monomorphize(field_ty, self.substs()); let field_ty = self.monomorphize(field_ty, self.substs());
@ -363,7 +363,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let usize = self.tcx.types.usize; let usize = self.tcx.types.usize;
let n = self.value_to_primval(n_ptr, usize)?.to_u64()?; 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); assert!(n < len, "Tried to access element {} of array/slice with length {}", n, len);
let ptr = base_ptr.offset(n * elem_size)?; let ptr = base_ptr.offset(n * elem_size, self.memory.layout)?;
(ptr, LvalueExtra::None) (ptr, LvalueExtra::None)
} }
@ -384,7 +384,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
u64::from(offset) u64::from(offset)
}; };
let ptr = base_ptr.offset(index * elem_size)?; let ptr = base_ptr.offset(index * elem_size, self.memory.layout)?;
(ptr, LvalueExtra::None) (ptr, LvalueExtra::None)
} }
@ -398,7 +398,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let (elem_ty, n) = base.elem_ty_and_len(base_ty); 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"); let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized");
assert!(u64::from(from) <= n - u64::from(to)); assert!(u64::from(from) <= n - u64::from(to));
let ptr = base_ptr.offset(u64::from(from) * elem_size)?; let ptr = base_ptr.offset(u64::from(from) * elem_size, self.memory.layout)?;
let extra = LvalueExtra::Length(n - u64::from(to) - u64::from(from)); let extra = LvalueExtra::Length(n - u64::from(to) - u64::from(from));
(ptr, extra) (ptr, extra)
} }

View file

@ -60,11 +60,11 @@ impl Pointer {
Pointer { alloc_id, offset } Pointer { alloc_id, offset }
} }
pub fn wrapping_signed_offset<'tcx>(self, i: i64) -> Self { pub fn wrapping_signed_offset<'tcx>(self, i: i64, layout: &TargetDataLayout) -> Self {
Pointer::new(self.alloc_id, self.offset.wrapping_add(i as u64)) Pointer::new(self.alloc_id, (self.offset.wrapping_add(i as u64) as u128 % (1u128 << layout.pointer_size.bits())) as u64)
} }
pub fn signed_offset<'tcx>(self, i: i64) -> EvalResult<'tcx, Self> { pub fn signed_offset<'tcx>(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
// FIXME: is it possible to over/underflow here? // FIXME: is it possible to over/underflow here?
if i < 0 { if i < 0 {
// trickery to ensure that i64::min_value() works fine // trickery to ensure that i64::min_value() works fine
@ -76,13 +76,17 @@ impl Pointer {
Err(EvalError::OverflowingPointerMath) Err(EvalError::OverflowingPointerMath)
} }
} else { } else {
self.offset(i as u64) self.offset(i as u64, layout)
} }
} }
pub fn offset<'tcx>(self, i: u64) -> EvalResult<'tcx, Self> { pub fn offset<'tcx>(self, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
if let Some(res) = self.offset.checked_add(i) { if let Some(res) = self.offset.checked_add(i) {
Ok(Pointer::new(self.alloc_id, res)) if res as u128 >= (1u128 << layout.pointer_size.bits()) {
Err(EvalError::OverflowingPointerMath)
} else {
Ok(Pointer::new(self.alloc_id, res))
}
} else { } else {
Err(EvalError::OverflowingPointerMath) Err(EvalError::OverflowingPointerMath)
} }
@ -283,7 +287,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
alloc.undef_mask.grow(amount, false); alloc.undef_mask.grow(amount, false);
} else if size > new_size { } else if size > new_size {
self.memory_usage -= size - new_size; self.memory_usage -= size - new_size;
self.clear_relocations(ptr.offset(new_size)?, size - new_size)?; self.clear_relocations(ptr.offset(new_size, self.layout)?, size - new_size)?;
let alloc = self.get_mut(ptr.alloc_id)?; let alloc = self.get_mut(ptr.alloc_id)?;
// `as usize` is fine here, since it is smaller than `size`, which came from a usize // `as usize` is fine here, since it is smaller than `size`, which came from a usize
alloc.bytes.truncate(new_size as usize); alloc.bytes.truncate(new_size as usize);
@ -595,7 +599,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
return Ok(&[]); return Ok(&[]);
} }
self.check_align(ptr, align, size)?; self.check_align(ptr, align, size)?;
self.check_bounds(ptr.offset(size)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) self.check_bounds(ptr.offset(size, self.layout)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
let alloc = self.get(ptr.alloc_id)?; let alloc = self.get(ptr.alloc_id)?;
assert_eq!(ptr.offset as usize as u64, ptr.offset); assert_eq!(ptr.offset as usize as u64, ptr.offset);
assert_eq!(size as usize as u64, size); assert_eq!(size as usize as u64, size);
@ -608,7 +612,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
return Ok(&mut []); return Ok(&mut []);
} }
self.check_align(ptr, align, size)?; self.check_align(ptr, align, size)?;
self.check_bounds(ptr.offset(size)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) self.check_bounds(ptr.offset(size, self.layout)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
let alloc = self.get_mut(ptr.alloc_id)?; let alloc = self.get_mut(ptr.alloc_id)?;
assert_eq!(ptr.offset as usize as u64, ptr.offset); assert_eq!(ptr.offset as usize as u64, ptr.offset);
assert_eq!(size as usize as u64, size); assert_eq!(size as usize as u64, size);
@ -930,7 +934,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
fn check_relocation_edges(&self, ptr: Pointer, size: u64) -> EvalResult<'tcx> { fn check_relocation_edges(&self, ptr: Pointer, size: u64) -> EvalResult<'tcx> {
let overlapping_start = self.relocations(ptr, 0)?.count(); let overlapping_start = self.relocations(ptr, 0)?.count();
let overlapping_end = self.relocations(ptr.offset(size)?, 0)?.count(); let overlapping_end = self.relocations(ptr.offset(size, self.layout)?, 0)?.count();
if overlapping_start + overlapping_end != 0 { if overlapping_start + overlapping_end != 0 {
return Err(EvalError::ReadPointerAsBytes); return Err(EvalError::ReadPointerAsBytes);
} }

View file

@ -305,7 +305,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
match arg_val { match arg_val {
Value::ByRef(ptr) => { Value::ByRef(ptr) => {
for ((offset, ty), arg_local) in offsets.zip(fields).zip(arg_locals) { for ((offset, ty), arg_local) in offsets.zip(fields).zip(arg_locals) {
let arg = Value::ByRef(ptr.offset(offset)?); let arg = Value::ByRef(ptr.offset(offset, self.memory.layout)?);
let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
trace!("writing arg {:?} to {:?} (type: {})", arg, dest, ty); trace!("writing arg {:?} to {:?} (type: {})", arg, dest, ty);
self.write_value(arg, dest, ty)?; self.write_value(arg, dest, ty)?;
@ -387,7 +387,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
ty::InstanceDef::Virtual(_, idx) => { ty::InstanceDef::Virtual(_, idx) => {
let ptr_size = self.memory.pointer_size(); let ptr_size = self.memory.pointer_size();
let (_, vtable) = self.eval_operand(&arg_operands[0])?.expect_ptr_vtable_pair(&self.memory)?; let (_, vtable) = self.eval_operand(&arg_operands[0])?.expect_ptr_vtable_pair(&self.memory)?;
let fn_ptr = self.memory.read_ptr(vtable.offset(ptr_size * (idx as u64 + 3))?)?; let fn_ptr = self.memory.read_ptr(vtable.offset(ptr_size * (idx as u64 + 3), self.memory.layout)?)?;
let instance = self.memory.get_fn(fn_ptr.alloc_id)?; let instance = self.memory.get_fn(fn_ptr.alloc_id)?;
let mut arg_operands = arg_operands.to_vec(); let mut arg_operands = arg_operands.to_vec();
let ty = self.operand_ty(&arg_operands[0]); let ty = self.operand_ty(&arg_operands[0]);
@ -473,7 +473,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
let (offset, ty) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?; let (offset, ty) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?;
let nonnull = adt_ptr.offset(offset.bytes())?; let nonnull = adt_ptr.offset(offset.bytes(), self.memory.layout)?;
trace!("struct wrapped nullable pointer type: {}", ty); trace!("struct wrapped nullable pointer type: {}", ty);
// only the pointer part of a fat pointer is used for this space optimization // only the pointer part of a fat pointer is used for this space optimization
let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield"); let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield");
@ -654,7 +654,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8; let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8;
let num = self.value_to_primval(args[2], usize)?.to_u64()?; let num = self.value_to_primval(args[2], usize)?.to_u64()?;
if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(|&c| c == val) { if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(|&c| c == val) {
let new_ptr = ptr.offset(num - idx as u64 - 1)?; let new_ptr = ptr.offset(num - idx as u64 - 1, self.memory.layout)?;
self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
} else { } else {
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?; self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
@ -666,7 +666,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8; let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8;
let num = self.value_to_primval(args[2], usize)?.to_u64()?; let num = self.value_to_primval(args[2], usize)?.to_u64()?;
if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(|&c| c == val) { if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(|&c| c == val) {
let new_ptr = ptr.offset(idx as u64)?; let new_ptr = ptr.offset(idx as u64, self.memory.layout)?;
self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
} else { } else {
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?; self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;

View file

@ -56,14 +56,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let drop = self.memory.create_fn_alloc(drop); let drop = self.memory.create_fn_alloc(drop);
self.memory.write_ptr(vtable, drop)?; self.memory.write_ptr(vtable, drop)?;
self.memory.write_usize(vtable.offset(ptr_size)?, size)?; self.memory.write_usize(vtable.offset(ptr_size, self.memory.layout)?, size)?;
self.memory.write_usize(vtable.offset(ptr_size * 2)?, align)?; self.memory.write_usize(vtable.offset(ptr_size * 2, self.memory.layout)?, align)?;
for (i, method) in ::rustc::traits::get_vtable_methods(self.tcx, trait_ref).enumerate() { for (i, method) in ::rustc::traits::get_vtable_methods(self.tcx, trait_ref).enumerate() {
if let Some((def_id, substs)) = method { if let Some((def_id, substs)) = method {
let instance = ::eval_context::resolve(self.tcx, def_id, substs); let instance = ::eval_context::resolve(self.tcx, def_id, substs);
let fn_ptr = self.memory.create_fn_alloc(instance); let fn_ptr = self.memory.create_fn_alloc(instance);
self.memory.write_ptr(vtable.offset(ptr_size * (3 + i as u64))?, fn_ptr)?; self.memory.write_ptr(vtable.offset(ptr_size * (3 + i as u64), self.memory.layout)?, fn_ptr)?;
} }
} }
@ -88,8 +88,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
pub fn read_size_and_align_from_vtable(&self, vtable: Pointer) -> EvalResult<'tcx, (u64, u64)> { pub fn read_size_and_align_from_vtable(&self, vtable: Pointer) -> EvalResult<'tcx, (u64, u64)> {
let pointer_size = self.memory.pointer_size(); let pointer_size = self.memory.pointer_size();
let size = self.memory.read_usize(vtable.offset(pointer_size)?)?; let size = self.memory.read_usize(vtable.offset(pointer_size, self.memory.layout)?)?;
let align = self.memory.read_usize(vtable.offset(pointer_size * 2)?)?; let align = self.memory.read_usize(vtable.offset(pointer_size * 2, self.memory.layout)?)?;
Ok((size, align)) Ok((size, align))
} }

View file

@ -90,7 +90,7 @@ impl<'a, 'tcx: 'a> Value {
match *self { match *self {
ByRef(ref_ptr) => { ByRef(ref_ptr) => {
let ptr = mem.read_ptr(ref_ptr)?; let ptr = mem.read_ptr(ref_ptr)?;
let vtable = mem.read_ptr(ref_ptr.offset(mem.pointer_size())?)?; let vtable = mem.read_ptr(ref_ptr.offset(mem.pointer_size(), mem.layout)?)?;
Ok((ptr, vtable)) Ok((ptr, vtable))
} }
@ -105,7 +105,7 @@ impl<'a, 'tcx: 'a> Value {
match *self { match *self {
ByRef(ref_ptr) => { ByRef(ref_ptr) => {
let ptr = mem.read_ptr(ref_ptr)?; let ptr = mem.read_ptr(ref_ptr)?;
let len = mem.read_usize(ref_ptr.offset(mem.pointer_size())?)?; let len = mem.read_usize(ref_ptr.offset(mem.pointer_size(), mem.layout)?)?;
Ok((ptr, len)) Ok((ptr, len))
}, },
ByValPair(ptr, val) => { ByValPair(ptr, val) => {