Skip to content

Commit 526b8ae

Browse files
authored
Merge pull request #623 from RalfJung/fat-ptr-eq
Fix comparing fat pointers
2 parents b468789 + e630175 commit 526b8ae

File tree

8 files changed

+73
-47
lines changed

8 files changed

+73
-47
lines changed

rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
nightly-2019-02-14
1+
nightly-2019-02-15

src/bin/cargo-miri.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ path = "lib.rs"
266266
let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) };
267267
std::env::set_var("MIRI_SYSROOT", &sysroot);
268268
if !ask_user {
269-
println!("A libstd for miri is now available in `{}`", sysroot.display());
269+
println!("A libstd for Miri is now available in `{}`", sysroot.display());
270270
}
271271
}
272272

src/intrinsic.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc::ty;
55
use rustc::mir::interpret::{EvalResult, PointerArithmetic};
66

77
use crate::{
8-
PlaceTy, OpTy, Immediate, Scalar, ScalarMaybeUndef, Borrow,
8+
PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Borrow,
99
OperatorEvalContextExt
1010
};
1111

@@ -80,11 +80,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
8080

8181
_ if intrinsic_name.starts_with("atomic_cxchg") => {
8282
let ptr = this.deref_operand(args[0])?;
83-
let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op_imm()`
83+
let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op()`
8484
let new = this.read_scalar(args[2])?;
85-
let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op_imm()`
86-
// binary_op_imm will bail if either of them is not a scalar
87-
let (eq, _) = this.binary_op_imm(mir::BinOp::Eq, old, expect_old)?;
85+
let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op()`
86+
// binary_op will bail if either of them is not a scalar
87+
let (eq, _) = this.binary_op(mir::BinOp::Eq, old, expect_old)?;
8888
let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into());
8989
this.write_immediate(res, dest)?; // old value is returned
9090
// update ptr depending on comparison
@@ -140,9 +140,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
140140
_ => bug!(),
141141
};
142142
// Atomics wrap around on overflow.
143-
let (val, _overflowed) = this.binary_op_imm(op, old, rhs)?;
143+
let (val, _overflowed) = this.binary_op(op, old, rhs)?;
144144
let val = if neg {
145-
this.unary_op(mir::UnOp::Not, val, old.layout)?
145+
this.unary_op(mir::UnOp::Not, ImmTy::from_scalar(val, old.layout))?
146146
} else {
147147
val
148148
};
@@ -239,7 +239,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
239239
let a = this.read_immediate(args[0])?;
240240
let b = this.read_immediate(args[1])?;
241241
// check x % y != 0
242-
if this.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 {
242+
if this.binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 {
243243
return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b)));
244244
}
245245
this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?;

src/lib.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::collections::HashMap;
1717
use std::borrow::Cow;
1818

1919
use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
20-
use rustc::ty::layout::{TyLayout, LayoutOf, Size, Align};
20+
use rustc::ty::layout::{LayoutOf, Size, Align};
2121
use rustc::hir::{self, def_id::DefId};
2222
use rustc::mir;
2323

@@ -406,12 +406,10 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
406406
fn ptr_op(
407407
ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>,
408408
bin_op: mir::BinOp,
409-
left: Scalar<Borrow>,
410-
left_layout: TyLayout<'tcx>,
411-
right: Scalar<Borrow>,
412-
right_layout: TyLayout<'tcx>,
409+
left: ImmTy<'tcx, Borrow>,
410+
right: ImmTy<'tcx, Borrow>,
413411
) -> EvalResult<'tcx, (Scalar<Borrow>, bool)> {
414-
ecx.ptr_op(bin_op, left, left_layout, right, right_layout)
412+
ecx.ptr_op(bin_op, left, right)
415413
}
416414

417415
fn box_alloc(

src/operator.rs

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rustc::ty::{Ty, layout::TyLayout};
1+
use rustc::ty::Ty;
22
use rustc::mir;
33

44
use crate::*;
@@ -7,10 +7,8 @@ pub trait EvalContextExt<'tcx> {
77
fn ptr_op(
88
&self,
99
bin_op: mir::BinOp,
10-
left: Scalar<Borrow>,
11-
left_layout: TyLayout<'tcx>,
12-
right: Scalar<Borrow>,
13-
right_layout: TyLayout<'tcx>,
10+
left: ImmTy<'tcx, Borrow>,
11+
right: ImmTy<'tcx, Borrow>,
1412
) -> EvalResult<'tcx, (Scalar<Borrow>, bool)>;
1513

1614
fn ptr_int_arithmetic(
@@ -25,7 +23,6 @@ pub trait EvalContextExt<'tcx> {
2523
&self,
2624
left: Scalar<Borrow>,
2725
right: Scalar<Borrow>,
28-
size: Size,
2926
) -> EvalResult<'tcx, bool>;
3027

3128
fn pointer_offset_inbounds(
@@ -40,14 +37,34 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
4037
fn ptr_op(
4138
&self,
4239
bin_op: mir::BinOp,
43-
left: Scalar<Borrow>,
44-
left_layout: TyLayout<'tcx>,
45-
right: Scalar<Borrow>,
46-
right_layout: TyLayout<'tcx>,
40+
left: ImmTy<'tcx, Borrow>,
41+
right: ImmTy<'tcx, Borrow>,
4742
) -> EvalResult<'tcx, (Scalar<Borrow>, bool)> {
4843
use rustc::mir::BinOp::*;
4944

50-
trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right);
45+
trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right);
46+
47+
// Operations that support fat pointers
48+
match bin_op {
49+
Eq | Ne => {
50+
let eq = match (*left, *right) {
51+
(Immediate::Scalar(left), Immediate::Scalar(right)) =>
52+
self.ptr_eq(left.not_undef()?, right.not_undef()?)?,
53+
(Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) =>
54+
self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? &&
55+
self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?,
56+
_ => bug!("Type system should not allow comparing Scalar with ScalarPair"),
57+
};
58+
return Ok((Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false));
59+
}
60+
_ => {},
61+
}
62+
63+
// Now we expect no more fat pointers
64+
let left_layout = left.layout;
65+
let left = left.to_scalar()?;
66+
let right_layout = right.layout;
67+
let right = right.to_scalar()?;
5168
debug_assert!(left.is_ptr() || right.is_ptr() || bin_op == Offset);
5269

5370
match bin_op {
@@ -63,11 +80,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
6380
)?;
6481
Ok((ptr, false))
6582
}
66-
// These work on anything
67-
Eq =>
68-
Ok((Scalar::from_bool(self.ptr_eq(left, right, left_layout.size)?), false)),
69-
Ne =>
70-
Ok((Scalar::from_bool(!self.ptr_eq(left, right, left_layout.size)?), false)),
7183
// These need both to be pointer, and fail if they are not in the same location
7284
Lt | Le | Gt | Ge | Sub if left.is_ptr() && right.is_ptr() => {
7385
let left = left.to_ptr().expect("we checked is_ptr");
@@ -85,8 +97,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
8597
let layout = self.layout_of(self.tcx.types.usize)?;
8698
return self.binary_op(
8799
Sub,
88-
left_offset, layout,
89-
right_offset, layout,
100+
ImmTy::from_scalar(left_offset, layout),
101+
ImmTy::from_scalar(right_offset, layout),
90102
)
91103
}
92104
_ => bug!("We already established it has to be one of these operators."),
@@ -126,8 +138,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, '
126138
&self,
127139
left: Scalar<Borrow>,
128140
right: Scalar<Borrow>,
129-
size: Size,
130141
) -> EvalResult<'tcx, bool> {
142+
let size = self.pointer_size();
131143
Ok(match (left, right) {
132144
(Scalar::Bits { .. }, Scalar::Bits { .. }) =>
133145
left.to_bits(size)? == right.to_bits(size)?,

tests/run-pass/async-fn.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
futures_api,
55
)]
66

7-
use std::{future::Future, pin::Pin, task::Poll};
7+
use std::{future::Future, pin::Pin, task::Poll, ptr};
8+
use std::task::{Waker, RawWaker, RawWakerVTable};
89

910
// See if we can run a basic `async fn`
1011
pub async fn foo(x: &u32, y: u32) -> u32 {
@@ -17,18 +18,23 @@ pub async fn foo(x: &u32, y: u32) -> u32 {
1718
*x + y + *a
1819
}
1920

20-
fn main() {
21-
use std::{sync::Arc, task::{Wake, local_waker}};
21+
fn raw_waker_clone(_this: *const ()) -> RawWaker {
22+
panic!("unimplemented");
23+
}
24+
fn raw_waker_wake(_this: *const ()) {
25+
panic!("unimplemented");
26+
}
27+
fn raw_waker_drop(_this: *const ()) {}
2228

23-
struct NoWake;
24-
impl Wake for NoWake {
25-
fn wake(_arc_self: &Arc<Self>) {
26-
panic!();
27-
}
28-
}
29+
static RAW_WAKER: RawWakerVTable = RawWakerVTable {
30+
clone: raw_waker_clone,
31+
wake: raw_waker_wake,
32+
drop: raw_waker_drop,
33+
};
2934

30-
let lw = unsafe { local_waker(Arc::new(NoWake)) };
35+
fn main() {
3136
let x = 5;
3237
let mut fut = foo(&x, 7);
33-
assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&lw), Poll::Ready(31));
38+
let waker = unsafe { Waker::new_unchecked(RawWaker::new(ptr::null(), &RAW_WAKER)) };
39+
assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&waker), Poll::Ready(31));
3440
}

tests/run-pass/hashmap.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ fn main() {
2121
}
2222
assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2);
2323

24-
// TODO: Test Entry API
24+
// TODO: Test Entry API, Iterators, ...
2525
}

tests/run-pass/rc.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::cell::{Cell, RefCell};
22
use std::rc::Rc;
33
use std::sync::Arc;
4+
use std::fmt::Debug;
45

56
fn rc_refcell() {
67
let r = Rc::new(RefCell::new(42));
@@ -60,7 +61,16 @@ fn rc_from() {
6061
check_unique_rc::<str>(Rc::from("Hello, World!"));
6162
}
6263

64+
fn rc_fat_ptr_eq() {
65+
let p = Rc::new(1) as Rc<Debug>;
66+
let a: *const Debug = &*p;
67+
let r = Rc::into_raw(p);
68+
assert!(a == r);
69+
drop(unsafe { Rc::from_raw(r) });
70+
}
71+
6372
fn main() {
73+
rc_fat_ptr_eq();
6474
rc_refcell();
6575
rc_refcell2();
6676
rc_cell();

0 commit comments

Comments
 (0)