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

@@ -60,11 +60,11 @@ impl Pointer {
Pointer { alloc_id, offset }
}
pub fn wrapping_signed_offset<'tcx>(self, i: i64) -> Self {
Pointer::new(self.alloc_id, self.offset.wrapping_add(i as u64))
pub fn wrapping_signed_offset<'tcx>(self, i: i64, layout: &TargetDataLayout) -> Self {
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?
if i < 0 {
// trickery to ensure that i64::min_value() works fine
@@ -76,13 +76,17 @@ impl Pointer {
Err(EvalError::OverflowingPointerMath)
}
} 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) {
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 {
Err(EvalError::OverflowingPointerMath)
}
@@ -283,7 +287,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
alloc.undef_mask.grow(amount, false);
} else if 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)?;
// `as usize` is fine here, since it is smaller than `size`, which came from a usize
alloc.bytes.truncate(new_size as usize);
@@ -595,7 +599,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
return Ok(&[]);
}
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)?;
assert_eq!(ptr.offset as usize as u64, ptr.offset);
assert_eq!(size as usize as u64, size);
@@ -608,7 +612,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
return Ok(&mut []);
}
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)?;
assert_eq!(ptr.offset as usize as u64, ptr.offset);
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> {
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 {
return Err(EvalError::ReadPointerAsBytes);
}