1 #![allow(unknown_lints)]
4 use error::{EvalError, EvalResult};
5 use memory::{Memory, MemoryPointer, HasMemory, HasDataLayout};
7 pub(super) fn bytes_to_f32(bytes: u128) -> f32 {
8 f32::from_bits(bytes as u32)
11 pub(super) fn bytes_to_f64(bytes: u128) -> f64 {
12 f64::from_bits(bytes as u64)
15 pub(super) fn f32_to_bytes(f: f32) -> u128 {
19 pub(super) fn f64_to_bytes(f: f64) -> u128 {
23 /// A `Value` represents a single self-contained Rust value.
25 /// A `Value` can either refer to a block of memory inside an allocation (`ByRef`) or to a primitve
26 /// value held directly, outside of any allocation (`ByVal`). For `ByRef`-values, we remember
27 /// whether the pointer is supposed to be aligned or not (also see Lvalue).
29 /// For optimization of a few very common cases, there is also a representation for a pair of
30 /// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary
31 /// operations and fat pointers. This idea was taken from rustc's trans.
32 #[derive(Clone, Copy, Debug)]
36 ByValPair(PrimVal, PrimVal),
39 /// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally.
40 /// This type clears up a few APIs where having a `PrimVal` argument for something that is
41 /// potentially an integer pointer or a pointer to an allocation was unclear.
43 /// I (@oli-obk) believe it is less easy to mix up generic primvals and primvals that are just
44 /// the representation of pointers. Also all the sites that convert between primvals and pointers
45 /// are explicit now (and rare!)
46 #[derive(Clone, Copy, Debug)]
52 pub fn null() -> Self {
53 PrimVal::Bytes(0).into()
55 pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
58 pub fn into_inner_primval(self) -> PrimVal {
62 pub(crate) fn signed_offset<'a, L: HasDataLayout<'a>>(self, i: i64, layout: L) -> EvalResult<'tcx, Self> {
64 PrimVal::Bytes(b) => {
65 assert_eq!(b as u64 as u128, b);
66 Ok(Pointer::from(PrimVal::Bytes(layout.signed_offset(b as u64, i)? as u128)))
68 PrimVal::Ptr(ptr) => ptr.signed_offset(i, layout).map(Pointer::from),
69 PrimVal::Undef => Err(EvalError::ReadUndefBytes),
73 pub(crate) fn offset<'a, L: HasDataLayout<'a>>(self, i: u64, layout: L) -> EvalResult<'tcx, Self> {
75 PrimVal::Bytes(b) => {
76 assert_eq!(b as u64 as u128, b);
77 Ok(Pointer::from(PrimVal::Bytes(layout.offset(b as u64, i)? as u128)))
79 PrimVal::Ptr(ptr) => ptr.offset(i, layout).map(Pointer::from),
80 PrimVal::Undef => Err(EvalError::ReadUndefBytes),
84 pub(crate) fn wrapping_signed_offset<'a, L: HasDataLayout<'a>>(self, i: i64, layout: L) -> EvalResult<'tcx, Self> {
86 PrimVal::Bytes(b) => {
87 assert_eq!(b as u64 as u128, b);
88 Ok(Pointer::from(PrimVal::Bytes(layout.wrapping_signed_offset(b as u64, i) as u128)))
90 PrimVal::Ptr(ptr) => Ok(Pointer::from(ptr.wrapping_signed_offset(i, layout))),
91 PrimVal::Undef => Err(EvalError::ReadUndefBytes),
95 pub fn is_null(self) -> EvalResult<'tcx, bool> {
97 PrimVal::Bytes(b) => Ok(b == 0),
98 PrimVal::Ptr(_) => Ok(false),
99 PrimVal::Undef => Err(EvalError::ReadUndefBytes),
103 pub fn to_value_with_len(self, len: u64) -> Value {
104 Value::ByValPair(self.primval, PrimVal::from_u128(len as u128))
107 pub fn to_value_with_vtable(self, vtable: MemoryPointer) -> Value {
108 Value::ByValPair(self.primval, PrimVal::Ptr(vtable))
111 pub fn to_value(self) -> Value {
112 Value::ByVal(self.primval)
116 impl ::std::convert::From<PrimVal> for Pointer {
117 fn from(primval: PrimVal) -> Self {
122 impl ::std::convert::From<MemoryPointer> for Pointer {
123 fn from(ptr: MemoryPointer) -> Self {
124 PrimVal::Ptr(ptr).into()
128 /// A `PrimVal` represents an immediate, primitive value existing outside of a
129 /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
130 /// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes
131 /// of a simple value, a pointer into another `Allocation`, or be undefined.
132 #[derive(Clone, Copy, Debug)]
134 /// The raw bytes of a simple value.
137 /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
138 /// relocations, but a `PrimVal` is only large enough to contain one, so we just represent the
139 /// relocation and its associated offset together as a `MemoryPointer` here.
142 /// An undefined `PrimVal`, for representing values that aren't safe to examine, but are safe
143 /// to copy around, just like undefined bytes in an `Allocation`.
147 #[derive(Clone, Copy, Debug, PartialEq)]
148 pub enum PrimValKind {
149 I8, I16, I32, I64, I128,
150 U8, U16, U32, U64, U128,
158 impl<'a, 'tcx: 'a> Value {
160 pub(super) fn by_ref(ptr: Pointer) -> Self {
161 Value::ByRef(ptr, true)
164 /// Convert the value into a pointer (or a pointer-sized integer). If the value is a ByRef,
165 /// this may have to perform a load.
166 pub(super) fn into_ptr(&self, mem: &mut Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> {
169 ByRef(ptr, aligned) => {
170 mem.read_maybe_aligned(aligned, |mem| mem.read_ptr(ptr.to_ptr()?) )
172 ByVal(ptr) | ByValPair(ptr, _) => Ok(ptr.into()),
176 pub(super) fn into_ptr_vtable_pair(
178 mem: &mut Memory<'a, 'tcx>
179 ) -> EvalResult<'tcx, (Pointer, MemoryPointer)> {
182 ByRef(ref_ptr, aligned) => {
183 mem.read_maybe_aligned(aligned, |mem| {
184 let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?;
185 let vtable = mem.read_ptr(ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?)?;
186 Ok((ptr, vtable.to_ptr()?))
190 ByValPair(ptr, vtable) => Ok((ptr.into(), vtable.to_ptr()?)),
192 _ => bug!("expected ptr and vtable, got {:?}", self),
196 pub(super) fn into_slice(&self, mem: &mut Memory<'a, 'tcx>) -> EvalResult<'tcx, (Pointer, u64)> {
199 ByRef(ref_ptr, aligned) => {
200 mem.write_maybe_aligned(aligned, |mem| {
201 let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?;
202 let len = mem.read_usize(ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?)?;
206 ByValPair(ptr, val) => {
207 let len = val.to_u128()?;
208 assert_eq!(len as u64 as u128, len);
209 Ok((ptr.into(), len as u64))
211 ByVal(_) => bug!("expected ptr and length, got {:?}", self),
217 pub fn from_u128(n: u128) -> Self {
221 pub fn from_i128(n: i128) -> Self {
222 PrimVal::Bytes(n as u128)
225 pub fn from_f32(f: f32) -> Self {
226 PrimVal::Bytes(f32_to_bytes(f))
229 pub fn from_f64(f: f64) -> Self {
230 PrimVal::Bytes(f64_to_bytes(f))
233 pub fn from_bool(b: bool) -> Self {
234 PrimVal::Bytes(b as u128)
237 pub fn from_char(c: char) -> Self {
238 PrimVal::Bytes(c as u128)
241 pub fn to_bytes(self) -> EvalResult<'tcx, u128> {
243 PrimVal::Bytes(b) => Ok(b),
244 PrimVal::Ptr(_) => Err(EvalError::ReadPointerAsBytes),
245 PrimVal::Undef => Err(EvalError::ReadUndefBytes),
249 pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
251 PrimVal::Bytes(_) => Err(EvalError::ReadBytesAsPointer),
252 PrimVal::Ptr(p) => Ok(p),
253 PrimVal::Undef => Err(EvalError::ReadUndefBytes),
257 pub fn is_bytes(self) -> bool {
259 PrimVal::Bytes(_) => true,
264 pub fn is_ptr(self) -> bool {
266 PrimVal::Ptr(_) => true,
271 pub fn is_undef(self) -> bool {
273 PrimVal::Undef => true,
278 pub fn to_u128(self) -> EvalResult<'tcx, u128> {
282 pub fn to_u64(self) -> EvalResult<'tcx, u64> {
283 self.to_bytes().map(|b| {
284 assert_eq!(b as u64 as u128, b);
289 pub fn to_i32(self) -> EvalResult<'tcx, i32> {
290 self.to_bytes().map(|b| {
291 assert_eq!(b as i32 as u128, b);
296 pub fn to_i128(self) -> EvalResult<'tcx, i128> {
297 self.to_bytes().map(|b| b as i128)
300 pub fn to_i64(self) -> EvalResult<'tcx, i64> {
301 self.to_bytes().map(|b| {
302 assert_eq!(b as i64 as u128, b);
307 pub fn to_f32(self) -> EvalResult<'tcx, f32> {
308 self.to_bytes().map(bytes_to_f32)
311 pub fn to_f64(self) -> EvalResult<'tcx, f64> {
312 self.to_bytes().map(bytes_to_f64)
315 pub fn to_bool(self) -> EvalResult<'tcx, bool> {
316 match self.to_bytes()? {
319 _ => Err(EvalError::InvalidBool),
325 pub fn is_int(self) -> bool {
326 use self::PrimValKind::*;
328 I8 | I16 | I32 | I64 | I128 | U8 | U16 | U32 | U64 | U128 => true,
333 pub fn is_signed_int(self) -> bool {
334 use self::PrimValKind::*;
336 I8 | I16 | I32 | I64 | I128 => true,
341 pub fn is_float(self) -> bool {
342 use self::PrimValKind::*;
349 pub fn from_uint_size(size: u64) -> Self {
351 1 => PrimValKind::U8,
352 2 => PrimValKind::U16,
353 4 => PrimValKind::U32,
354 8 => PrimValKind::U64,
355 16 => PrimValKind::U128,
356 _ => bug!("can't make uint with size {}", size),
360 pub fn from_int_size(size: u64) -> Self {
362 1 => PrimValKind::I8,
363 2 => PrimValKind::I16,
364 4 => PrimValKind::I32,
365 8 => PrimValKind::I64,
366 16 => PrimValKind::I128,
367 _ => bug!("can't make int with size {}", size),
371 pub fn is_ptr(self) -> bool {
372 use self::PrimValKind::*;