]> git.lizzy.rs Git - rust.git/blob - src/operator.rs
fix comparing wide raw pointers
[rust.git] / src / operator.rs
1 use log::trace;
2
3 use rustc_middle::{mir, ty::Ty};
4
5 use crate::*;
6
7 pub trait EvalContextExt<'tcx> {
8     fn binary_ptr_op(
9         &self,
10         bin_op: mir::BinOp,
11         left: &ImmTy<'tcx, Tag>,
12         right: &ImmTy<'tcx, Tag>,
13     ) -> InterpResult<'tcx, (Scalar<Tag>, bool, Ty<'tcx>)>;
14
15     fn ptr_eq(&self, left: Scalar<Tag>, right: Scalar<Tag>) -> InterpResult<'tcx, bool>;
16 }
17
18 impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
19     fn binary_ptr_op(
20         &self,
21         bin_op: mir::BinOp,
22         left: &ImmTy<'tcx, Tag>,
23         right: &ImmTy<'tcx, Tag>,
24     ) -> InterpResult<'tcx, (Scalar<Tag>, bool, Ty<'tcx>)> {
25         use rustc_middle::mir::BinOp::*;
26
27         trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right);
28
29         Ok(match bin_op {
30             Eq | Ne => {
31                 // This supports fat pointers.
32                 #[rustfmt::skip]
33                 let eq = match (**left, **right) {
34                     (Immediate::Scalar(left), Immediate::Scalar(right)) => {
35                         self.ptr_eq(left.check_init()?, right.check_init()?)?
36                     }
37                     (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => {
38                         self.ptr_eq(left1.check_init()?, right1.check_init()?)?
39                             && self.ptr_eq(left2.check_init()?, right2.check_init()?)?
40                     }
41                     _ => bug!("Type system should not allow comparing Scalar with ScalarPair"),
42                 };
43                 (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false, self.tcx.types.bool)
44             }
45
46             Lt | Le | Gt | Ge => {
47                 let size = self.pointer_size();
48                 // Just compare the bits. ScalarPairs are compared lexicographically.
49                 // We thus always compare pairs and simply fill scalars up with 0.
50                 let left = match **left {
51                     Immediate::Scalar(l) => (l.check_init()?.to_bits(size)?, 0),
52                     Immediate::ScalarPair(l1, l2) =>
53                         (l1.check_init()?.to_bits(size)?, l2.check_init()?.to_bits(size)?),
54                 };
55                 let right = match **right {
56                     Immediate::Scalar(r) => (r.check_init()?.to_bits(size)?, 0),
57                     Immediate::ScalarPair(r1, r2) =>
58                         (r1.check_init()?.to_bits(size)?, r2.check_init()?.to_bits(size)?),
59                 };
60                 let res = match bin_op {
61                     Lt => left < right,
62                     Le => left <= right,
63                     Gt => left > right,
64                     Ge => left >= right,
65                     _ => bug!("We already established it has to be one of these operators."),
66                 };
67                 (Scalar::from_bool(res), false, self.tcx.types.bool)
68             }
69
70             Offset => {
71                 let pointee_ty =
72                     left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty;
73                 let ptr = self.ptr_offset_inbounds(
74                     self.scalar_to_ptr(left.to_scalar()?)?,
75                     pointee_ty,
76                     right.to_scalar()?.to_machine_isize(self)?,
77                 )?;
78                 (Scalar::from_maybe_pointer(ptr, self), false, left.layout.ty)
79             }
80
81             _ => bug!("Invalid operator on pointers: {:?}", bin_op),
82         })
83     }
84
85     fn ptr_eq(&self, left: Scalar<Tag>, right: Scalar<Tag>) -> InterpResult<'tcx, bool> {
86         let size = self.pointer_size();
87         // Just compare the integers.
88         let left = left.to_bits(size)?;
89         let right = right.to_bits(size)?;
90         Ok(left == right)
91     }
92 }