fix int ptr ops on 32bit

This commit is contained in:
Ralf Jung 2018-08-14 20:25:56 +02:00
parent 98a5b24ef7
commit 1179d4f8a4

View File

@ -20,7 +20,7 @@ pub trait EvalContextExt<'tcx> {
&self,
bin_op: mir::BinOp,
left: Pointer,
right: i128,
right: u128,
signed: bool,
) -> EvalResult<'tcx, (Scalar, bool)>;
}
@ -138,7 +138,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
self.ptr_int_arithmetic(
bin_op,
left.to_ptr()?,
right.to_bits(self.memory.pointer_size())? as i128,
right.to_bits(self.memory.pointer_size())?,
left_kind == isize,
).map(Some)
}
@ -150,7 +150,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
self.ptr_int_arithmetic(
bin_op,
right.to_ptr()?,
left.to_bits(self.memory.pointer_size())? as i128,
left.to_bits(self.memory.pointer_size())?,
left_kind == isize,
).map(Some)
}
@ -162,7 +162,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
&self,
bin_op: mir::BinOp,
left: Pointer,
right: i128,
right: u128,
signed: bool,
) -> EvalResult<'tcx, (Scalar, bool)> {
use rustc::mir::BinOp::*;
@ -174,23 +174,31 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
Ok(match bin_op {
Sub =>
// The only way this can overflow is by underflowing, so signdeness of the right operands does not matter
map_to_primval(left.overflowing_signed_offset(-right, self)),
map_to_primval(left.overflowing_signed_offset(-(right as i128), self)),
Add if signed =>
map_to_primval(left.overflowing_signed_offset(right, self)),
map_to_primval(left.overflowing_signed_offset(right as i128, self)),
Add if !signed =>
map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)),
BitAnd if !signed => {
let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi();
let base_mask : u64 = !(ptr_base_align - 1);
let right = right as u64;
let base_mask = {
// FIXME: Use interpret::truncate, once that takes a Size instead of a Layout
let shift = 128 - self.memory.pointer_size().bits();
let value = !(ptr_base_align as u128 - 1);
// truncate (shift left to drop out leftover values, shift right to fill with zeroes)
(value << shift) >> shift
};
let ptr_size = self.memory.pointer_size().bytes() as u8;
trace!("Ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}",
ptr_base_align, right, base_mask);
if right & base_mask == base_mask {
// Case 1: The base address bits are all preserved, i.e., right is all-1 there
(Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false)
let offset = (left.offset.bytes() as u128 & right) as u64;
(Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(offset))), false)
} else if right & base_mask == 0 {
// Case 2: The base address bits are all taken away, i.e., right is all-0 there
(Scalar::Bits { bits: (left.offset.bytes() & right) as u128, size: ptr_size }, false)
(Scalar::Bits { bits: (left.offset.bytes() as u128) & right, size: ptr_size }, false)
} else {
return err!(ReadPointerAsBytes);
}