Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update for rustc Scalar changes, test for pointer wrapping ICE #744

Merged
merged 3 commits into from
May 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1a56ec4dae92538ab6e0ecf993c61f3b50ed77cf
721268583759224d0f6476e0b8b196cc8afbdea0
5 changes: 3 additions & 2 deletions src/fn_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,11 +607,12 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
// Extract the function type out of the signature (that seems easier than constructing it ourselves).
let dtor = match this.read_scalar(args[1])?.not_undef()? {
Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?),
Scalar::Bits { bits: 0, size } => {
Scalar::Raw { data: 0, size } => {
// NULL pointer
assert_eq!(size as u64, this.memory().pointer_size().bytes());
None
},
Scalar::Bits { .. } => return err!(ReadBytesAsPointer),
Scalar::Raw { .. } => return err!(ReadBytesAsPointer),
};

// Figure out how large a pthread TLS key actually is.
Expand Down
22 changes: 10 additions & 12 deletions src/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
) -> EvalResult<'tcx, bool> {
let size = self.pointer_size();
Ok(match (left, right) {
(Scalar::Bits { .. }, Scalar::Bits { .. }) =>
(Scalar::Raw { .. }, Scalar::Raw { .. }) =>
left.to_bits(size)? == right.to_bits(size)?,
(Scalar::Ptr(left), Scalar::Ptr(right)) => {
// Comparison illegal if one of them is out-of-bounds, *unless* they
Expand All @@ -165,10 +165,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
}
}
// Comparing ptr and integer.
(Scalar::Ptr(ptr), Scalar::Bits { bits, size }) |
(Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => {
(Scalar::Ptr(ptr), Scalar::Raw { data, size }) |
(Scalar::Raw { data, size }, Scalar::Ptr(ptr)) => {
assert_eq!(size as u64, self.pointer_size().bytes());
let bits = bits as u64;
let bits = data as u64;

// Case I: Comparing real pointers with "small" integers.
// Really we should only do this for NULL, but pragmatically speaking on non-bare-metal systems,
Expand Down Expand Up @@ -262,7 +262,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
// 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;
let ptr_size = self.memory().pointer_size();
trace!("ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}",
ptr_base_align, right, base_mask);
if right & base_mask == base_mask {
Expand All @@ -278,7 +278,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
)
} 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() as u128) & right, size: ptr_size }, false)
let v = Scalar::from_uint((left.offset.bytes() as u128) & right, ptr_size);
(v, false)
} else {
return err!(ReadPointerAsBytes);
}
Expand All @@ -289,18 +290,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
// (Intuition: modulo a divisor leaks less information.)
let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes();
let right = right as u64;
let ptr_size = self.memory().pointer_size().bytes() as u8;
let ptr_size = self.memory().pointer_size();
if right == 1 {
// Modulo 1 is always 0.
(Scalar::Bits { bits: 0, size: ptr_size }, false)
(Scalar::from_uint(0u32, ptr_size), false)
} else if ptr_base_align % right == 0 {
// The base address would be cancelled out by the modulo operation, so we can
// just take the modulo of the offset.
(
Scalar::Bits {
bits: (left.offset.bytes() % right) as u128,
size: ptr_size
},
Scalar::from_uint((left.offset.bytes() % right) as u128, ptr_size),
false,
)
} else {
Expand Down
13 changes: 8 additions & 5 deletions tests/run-pass/ptr_arith_offset_overflow.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::ptr;

fn main() {
let v = [1i16, 2];
let x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element
let x = &mut ptr::null(); // going through memory as there are more sanity checks along that path
*x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element
// Adding 2*isize::max and then 1 is like substracting 1
let x = x.wrapping_offset(isize::max_value());
let x = x.wrapping_offset(isize::max_value());
let x = x.wrapping_offset(1);
assert_eq!(unsafe { *x }, 1);
*x = x.wrapping_offset(isize::max_value());
*x = x.wrapping_offset(isize::max_value());
*x = x.wrapping_offset(1);
assert_eq!(unsafe { **x }, 1);
}
7 changes: 7 additions & 0 deletions tests/run-pass/ptr_int_casts.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::mem;
use std::ptr;

fn eq_ref<T>(x: &T, y: &T) -> bool {
x as *const _ == y as *const _
Expand All @@ -11,6 +12,12 @@ fn main() {
assert_eq!(1 as *const i32 as usize, 1);
assert_eq!((1 as *const i32).wrapping_offset(4) as usize, 1 + 4*4);

// negative overflowing wrapping_offset (going through memory because
// this used to trigger an ICE on 32bit)
let val = &mut ptr::null();
*val = (1 as *const u8).wrapping_offset(-4);
assert_eq!(*val as usize, usize::max_value() - 2);

{ // ptr-int-ptr
let x = 13;
let mut y = &x as &_ as *const _ as usize;
Expand Down