value.rs 12.0 KB
Newer Older
1 2
#![allow(unknown_lints)]

3
use rustc::ty::layout::HasDataLayout;
4

R
rustfmt  
Ralf Jung 已提交
5
use super::{EvalResult, Memory, MemoryPointer, HasMemory, PointerArithmetic, Machine, PtrAndAlign};
6

O
Oliver Schneider 已提交
7
pub(super) fn bytes_to_f32(bytes: u128) -> f32 {
8
    f32::from_bits(bytes as u32)
9 10
}

O
Oliver Schneider 已提交
11
pub(super) fn bytes_to_f64(bytes: u128) -> f64 {
12
    f64::from_bits(bytes as u64)
13 14
}

O
Oliver Schneider 已提交
15
pub(super) fn f32_to_bytes(f: f32) -> u128 {
16
    f.to_bits() as u128
17 18
}

O
Oliver Schneider 已提交
19
pub(super) fn f64_to_bytes(f: f64) -> u128 {
20
    f.to_bits() as u128
21 22
}

23 24 25
/// A `Value` represents a single self-contained Rust value.
///
/// A `Value` can either refer to a block of memory inside an allocation (`ByRef`) or to a primitve
26 27
/// value held directly, outside of any allocation (`ByVal`).  For `ByRef`-values, we remember
/// whether the pointer is supposed to be aligned or not (also see Lvalue).
28 29 30 31 32
///
/// For optimization of a few very common cases, there is also a representation for a pair of
/// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary
/// operations and fat pointers. This idea was taken from rustc's trans.
#[derive(Clone, Copy, Debug)]
33
pub enum Value {
O
Oliver Schneider 已提交
34
    ByRef(PtrAndAlign),
35
    ByVal(PrimVal),
36
    ByValPair(PrimVal, PrimVal),
37 38
}

39 40 41
/// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally.
/// This type clears up a few APIs where having a `PrimVal` argument for something that is
/// potentially an integer pointer or a pointer to an allocation was unclear.
42 43 44 45
///
/// I (@oli-obk) believe it is less easy to mix up generic primvals and primvals that are just
/// the representation of pointers. Also all the sites that convert between primvals and pointers
/// are explicit now (and rare!)
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
#[derive(Clone, Copy, Debug)]
pub struct Pointer {
    primval: PrimVal,
}

impl<'tcx> Pointer {
    pub fn null() -> Self {
        PrimVal::Bytes(0).into()
    }
    pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
        self.primval.to_ptr()
    }
    pub fn into_inner_primval(self) -> PrimVal {
        self.primval
    }

62
    pub fn signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
63
        let layout = cx.data_layout();
64 65 66
        match self.primval {
            PrimVal::Bytes(b) => {
                assert_eq!(b as u64 as u128, b);
R
rustfmt  
Ralf Jung 已提交
67 68 69 70
                Ok(Pointer::from(
                    PrimVal::Bytes(layout.signed_offset(b as u64, i)? as u128),
                ))
            }
71
            PrimVal::Ptr(ptr) => ptr.signed_offset(i, layout).map(Pointer::from),
72
            PrimVal::Undef => err!(ReadUndefBytes),
73
        }
74 75
    }

76
    pub fn offset<C: HasDataLayout>(self, i: u64, cx: C) -> EvalResult<'tcx, Self> {
77
        let layout = cx.data_layout();
78 79 80
        match self.primval {
            PrimVal::Bytes(b) => {
                assert_eq!(b as u64 as u128, b);
R
rustfmt  
Ralf Jung 已提交
81 82 83 84
                Ok(Pointer::from(
                    PrimVal::Bytes(layout.offset(b as u64, i)? as u128),
                ))
            }
85
            PrimVal::Ptr(ptr) => ptr.offset(i, layout).map(Pointer::from),
86
            PrimVal::Undef => err!(ReadUndefBytes),
87
        }
88 89
    }

90
    pub fn wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
91
        let layout = cx.data_layout();
92 93 94
        match self.primval {
            PrimVal::Bytes(b) => {
                assert_eq!(b as u64 as u128, b);
R
rustfmt  
Ralf Jung 已提交
95 96 97 98
                Ok(Pointer::from(PrimVal::Bytes(
                    layout.wrapping_signed_offset(b as u64, i) as u128,
                )))
            }
99
            PrimVal::Ptr(ptr) => Ok(Pointer::from(ptr.wrapping_signed_offset(i, layout))),
100
            PrimVal::Undef => err!(ReadUndefBytes),
101
        }
102 103 104 105 106 107
    }

    pub fn is_null(self) -> EvalResult<'tcx, bool> {
        match self.primval {
            PrimVal::Bytes(b) => Ok(b == 0),
            PrimVal::Ptr(_) => Ok(false),
108
            PrimVal::Undef => err!(ReadUndefBytes),
109 110 111
        }
    }

O
Oliver Schneider 已提交
112 113
    pub fn to_value_with_len(self, len: u64) -> Value {
        Value::ByValPair(self.primval, PrimVal::from_u128(len as u128))
114
    }
O
Oliver Schneider 已提交
115 116 117 118 119

    pub fn to_value_with_vtable(self, vtable: MemoryPointer) -> Value {
        Value::ByValPair(self.primval, PrimVal::Ptr(vtable))
    }

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
    pub fn to_value(self) -> Value {
        Value::ByVal(self.primval)
    }
}

impl ::std::convert::From<PrimVal> for Pointer {
    fn from(primval: PrimVal) -> Self {
        Pointer { primval }
    }
}

impl ::std::convert::From<MemoryPointer> for Pointer {
    fn from(ptr: MemoryPointer) -> Self {
        PrimVal::Ptr(ptr).into()
    }
}

137 138 139 140
/// A `PrimVal` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes
/// of a simple value, a pointer into another `Allocation`, or be undefined.
141
#[derive(Clone, Copy, Debug)]
142
pub enum PrimVal {
143
    /// The raw bytes of a simple value.
O
Oliver Schneider 已提交
144
    Bytes(u128),
145

146 147
    /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
    /// relocations, but a `PrimVal` is only large enough to contain one, so we just represent the
148 149
    /// relocation and its associated offset together as a `MemoryPointer` here.
    Ptr(MemoryPointer),
150

151 152
    /// An undefined `PrimVal`, for representing values that aren't safe to examine, but are safe
    /// to copy around, just like undefined bytes in an `Allocation`.
153
    Undef,
154 155 156 157
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PrimValKind {
O
Oliver Schneider 已提交
158 159
    I8, I16, I32, I64, I128,
    U8, U16, U32, U64, U128,
160
    F32, F64,
R
rustfmt  
Ralf Jung 已提交
161
    Ptr, FnPtr,
162 163 164 165
    Bool,
    Char,
}

166
impl<'a, 'tcx: 'a> Value {
167
    #[inline]
168
    pub fn by_ref(ptr: Pointer) -> Self {
O
Oliver Schneider 已提交
169
        Value::ByRef(PtrAndAlign { ptr, aligned: true })
170 171
    }

172 173
    /// Convert the value into a pointer (or a pointer-sized integer).  If the value is a ByRef,
    /// this may have to perform a load.
R
rustfmt  
Ralf Jung 已提交
174 175 176 177
    pub fn into_ptr<M: Machine<'tcx>>(
        &self,
        mem: &Memory<'a, 'tcx, M>,
    ) -> EvalResult<'tcx, Pointer> {
178
        use self::Value::*;
179
        Ok(match *self {
O
Oliver Schneider 已提交
180
            ByRef(PtrAndAlign { ptr, aligned }) => {
181
                mem.read_maybe_aligned(aligned, |mem| mem.read_ptr_sized_unsigned(ptr.to_ptr()?))?
R
rustfmt  
Ralf Jung 已提交
182 183
            }
            ByVal(ptr) |
184 185
            ByValPair(ptr, _) => ptr,
        }.into())
186 187
    }

188
    pub(super) fn into_ptr_vtable_pair<M: Machine<'tcx>>(
S
Scott Olson 已提交
189
        &self,
R
rustfmt  
Ralf Jung 已提交
190
        mem: &Memory<'a, 'tcx, M>,
191
    ) -> EvalResult<'tcx, (Pointer, MemoryPointer)> {
192 193
        use self::Value::*;
        match *self {
R
rustfmt  
Ralf Jung 已提交
194 195 196 197
            ByRef(PtrAndAlign {
                      ptr: ref_ptr,
                      aligned,
                  }) => {
198
                mem.read_maybe_aligned(aligned, |mem| {
199 200
                    let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?)?.into();
                    let vtable = mem.read_ptr_sized_unsigned(
R
rustfmt  
Ralf Jung 已提交
201
                        ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?,
202 203
                    )?.to_ptr()?;
                    Ok((ptr, vtable))
204
                })
S
Scott Olson 已提交
205
            }
S
Scott Olson 已提交
206

207
            ByValPair(ptr, vtable) => Ok((ptr.into(), vtable.to_ptr()?)),
S
Scott Olson 已提交
208

209
            ByVal(PrimVal::Undef) => err!(ReadUndefBytes),
S
Scott Olson 已提交
210
            _ => bug!("expected ptr and vtable, got {:?}", self),
211 212 213
        }
    }

R
rustfmt  
Ralf Jung 已提交
214 215 216 217
    pub(super) fn into_slice<M: Machine<'tcx>>(
        &self,
        mem: &Memory<'a, 'tcx, M>,
    ) -> EvalResult<'tcx, (Pointer, u64)> {
218 219
        use self::Value::*;
        match *self {
R
rustfmt  
Ralf Jung 已提交
220 221 222 223
            ByRef(PtrAndAlign {
                      ptr: ref_ptr,
                      aligned,
                  }) => {
224
                mem.read_maybe_aligned(aligned, |mem| {
225 226
                    let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?)?.into();
                    let len = mem.read_ptr_sized_unsigned(
R
rustfmt  
Ralf Jung 已提交
227
                        ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?,
228
                    )?.to_bytes()? as u64;
229 230
                    Ok((ptr, len))
                })
R
rustfmt  
Ralf Jung 已提交
231
            }
232
            ByValPair(ptr, val) => {
O
Oliver Schneider 已提交
233 234
                let len = val.to_u128()?;
                assert_eq!(len as u64 as u128, len);
235
                Ok((ptr.into(), len as u64))
R
rustfmt  
Ralf Jung 已提交
236
            }
237
            ByVal(PrimVal::Undef) => err!(ReadUndefBytes),
238
            ByVal(_) => bug!("expected ptr and length, got {:?}", self),
239 240 241
        }
    }
}
242

243
impl<'tcx> PrimVal {
O
Oliver Schneider 已提交
244
    pub fn from_u128(n: u128) -> Self {
245
        PrimVal::Bytes(n)
246 247
    }

O
Oliver Schneider 已提交
248 249
    pub fn from_i128(n: i128) -> Self {
        PrimVal::Bytes(n as u128)
250 251 252
    }

    pub fn from_f32(f: f32) -> Self {
253
        PrimVal::Bytes(f32_to_bytes(f))
254 255 256
    }

    pub fn from_f64(f: f64) -> Self {
257
        PrimVal::Bytes(f64_to_bytes(f))
258 259
    }

260
    pub fn from_bool(b: bool) -> Self {
O
Oliver Schneider 已提交
261
        PrimVal::Bytes(b as u128)
262 263
    }

264
    pub fn from_char(c: char) -> Self {
O
Oliver Schneider 已提交
265
        PrimVal::Bytes(c as u128)
266 267
    }

O
Oliver Schneider 已提交
268
    pub fn to_bytes(self) -> EvalResult<'tcx, u128> {
269 270
        match self {
            PrimVal::Bytes(b) => Ok(b),
271 272
            PrimVal::Ptr(_) => err!(ReadPointerAsBytes),
            PrimVal::Undef => err!(ReadUndefBytes),
273
        }
274 275
    }

276
    pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
277
        match self {
278
            PrimVal::Bytes(_) => err!(ReadBytesAsPointer),
279
            PrimVal::Ptr(p) => Ok(p),
280
            PrimVal::Undef => err!(ReadUndefBytes),
281
        }
282 283
    }

R
Ralf Jung 已提交
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
    pub fn is_bytes(self) -> bool {
        match self {
            PrimVal::Bytes(_) => true,
            _ => false,
        }
    }

    pub fn is_ptr(self) -> bool {
        match self {
            PrimVal::Ptr(_) => true,
            _ => false,
        }
    }

    pub fn is_undef(self) -> bool {
        match self {
            PrimVal::Undef => true,
            _ => false,
        }
    }

O
Oliver Schneider 已提交
305
    pub fn to_u128(self) -> EvalResult<'tcx, u128> {
306
        self.to_bytes()
307 308
    }

O
Oliver Schneider 已提交
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    pub fn to_u64(self) -> EvalResult<'tcx, u64> {
        self.to_bytes().map(|b| {
            assert_eq!(b as u64 as u128, b);
            b as u64
        })
    }

    pub fn to_i32(self) -> EvalResult<'tcx, i32> {
        self.to_bytes().map(|b| {
            assert_eq!(b as i32 as u128, b);
            b as i32
        })
    }

    pub fn to_i128(self) -> EvalResult<'tcx, i128> {
        self.to_bytes().map(|b| b as i128)
    }

327
    pub fn to_i64(self) -> EvalResult<'tcx, i64> {
O
Oliver Schneider 已提交
328 329 330 331
        self.to_bytes().map(|b| {
            assert_eq!(b as i64 as u128, b);
            b as i64
        })
332 333
    }

334
    pub fn to_f32(self) -> EvalResult<'tcx, f32> {
335
        self.to_bytes().map(bytes_to_f32)
336 337
    }

338
    pub fn to_f64(self) -> EvalResult<'tcx, f64> {
339
        self.to_bytes().map(bytes_to_f64)
340 341
    }

342 343
    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
        match self.to_bytes()? {
344 345
            0 => Ok(false),
            1 => Ok(true),
346
            _ => err!(InvalidBool),
347 348
        }
    }
349 350
}

351 352 353 354
impl PrimValKind {
    pub fn is_int(self) -> bool {
        use self::PrimValKind::*;
        match self {
O
Oliver Schneider 已提交
355
            I8 | I16 | I32 | I64 | I128 | U8 | U16 | U32 | U64 | U128 => true,
356 357 358 359
            _ => false,
        }
    }

O
1 > -1  
Oliver Schneider 已提交
360 361 362 363 364 365 366 367
    pub fn is_signed_int(self) -> bool {
        use self::PrimValKind::*;
        match self {
            I8 | I16 | I32 | I64 | I128 => true,
            _ => false,
        }
    }

R
rustfmt  
Ralf Jung 已提交
368
    pub fn is_float(self) -> bool {
R
Ralf Jung 已提交
369 370 371 372 373 374 375
        use self::PrimValKind::*;
        match self {
            F32 | F64 => true,
            _ => false,
        }
    }

376 377 378 379 380 381
    pub fn from_uint_size(size: u64) -> Self {
        match size {
            1 => PrimValKind::U8,
            2 => PrimValKind::U16,
            4 => PrimValKind::U32,
            8 => PrimValKind::U64,
O
Oliver Schneider 已提交
382
            16 => PrimValKind::U128,
383 384 385 386 387 388 389 390 391 392
            _ => bug!("can't make uint with size {}", size),
        }
    }

    pub fn from_int_size(size: u64) -> Self {
        match size {
            1 => PrimValKind::I8,
            2 => PrimValKind::I16,
            4 => PrimValKind::I32,
            8 => PrimValKind::I64,
O
Oliver Schneider 已提交
393
            16 => PrimValKind::I128,
394 395 396
            _ => bug!("can't make int with size {}", size),
        }
    }
397 398 399 400 401 402 403 404

    pub fn is_ptr(self) -> bool {
        use self::PrimValKind::*;
        match self {
            Ptr | FnPtr => true,
            _ => false,
        }
    }
405
}