1 #![allow(unknown_lints)]
4 use rustc::ty::layout::HasDataLayout;
8 Memory, MemoryPointer, HasMemory, PointerArithmetic,
12 pub(super) fn bytes_to_f32(bytes: u128) -> f32 {
13 f32::from_bits(bytes as u32)
16 pub(super) fn bytes_to_f64(bytes: u128) -> f64 {
17 f64::from_bits(bytes as u64)
20 pub(super) fn f32_to_bytes(f: f32) -> u128 {
24 pub(super) fn f64_to_bytes(f: f64) -> u128 {
28 /// A `Value` represents a single self-contained Rust value.
30 /// A `Value` can either refer to a block of memory inside an allocation (`ByRef`) or to a primitve
31 /// value held directly, outside of any allocation (`ByVal`). For `ByRef`-values, we remember
32 /// whether the pointer is supposed to be aligned or not (also see Lvalue).
34 /// For optimization of a few very common cases, there is also a representation for a pair of
35 /// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary
36 /// operations and fat pointers. This idea was taken from rustc's trans.
37 #[derive(Clone, Copy, Debug)]
39 ByRef { ptr: Pointer, aligned: bool},
41 ByValPair(PrimVal, PrimVal),
44 /// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally.
45 /// This type clears up a few APIs where having a `PrimVal` argument for something that is
46 /// potentially an integer pointer or a pointer to an allocation was unclear.
48 /// I (@oli-obk) believe it is less easy to mix up generic primvals and primvals that are just
49 /// the representation of pointers. Also all the sites that convert between primvals and pointers
50 /// are explicit now (and rare!)
51 #[derive(Clone, Copy, Debug)]
57 pub fn null() -> Self {
58 PrimVal::Bytes(0).into()
60 pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
63 pub fn into_inner_primval(self) -> PrimVal {
67 pub fn signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
68 let layout = cx.data_layout();
70 PrimVal::Bytes(b) => {
71 assert_eq!(b as u64 as u128, b);
72 Ok(Pointer::from(PrimVal::Bytes(layout.signed_offset(b as u64, i)? as u128)))
74 PrimVal::Ptr(ptr) => ptr.signed_offset(i, layout).map(Pointer::from),
75 PrimVal::Undef => Err(EvalError::ReadUndefBytes),
79 pub fn offset<C: HasDataLayout>(self, i: u64, cx: C) -> EvalResult<'tcx, Self> {
80 let layout = cx.data_layout();
82 PrimVal::Bytes(b) => {
83 assert_eq!(b as u64 as u128, b);
84 Ok(Pointer::from(PrimVal::Bytes(layout.offset(b as u64, i)? as u128)))
86 PrimVal::Ptr(ptr) => ptr.offset(i, layout).map(Pointer::from),
87 PrimVal::Undef => Err(EvalError::ReadUndefBytes),
91 pub fn wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
92 let layout = cx.data_layout();
94 PrimVal::Bytes(b) => {
95 assert_eq!(b as u64 as u128, b);
96 Ok(Pointer::from(PrimVal::Bytes(layout.wrapping_signed_offset(b as u64, i) as u128)))
98 PrimVal::Ptr(ptr) => Ok(Pointer::from(ptr.wrapping_signed_offset(i, layout))),
99 PrimVal::Undef => Err(EvalError::ReadUndefBytes),
103 pub fn is_null(self) -> EvalResult<'tcx, bool> {
105 PrimVal::Bytes(b) => Ok(b == 0),
106 PrimVal::Ptr(_) => Ok(false),
107 PrimVal::Undef => Err(EvalError::ReadUndefBytes),
111 pub fn to_value_with_len(self, len: u64) -> Value {
112 Value::ByValPair(self.primval, PrimVal::from_u128(len as u128))
115 pub fn to_value_with_vtable(self, vtable: MemoryPointer) -> Value {
116 Value::ByValPair(self.primval, PrimVal::Ptr(vtable))
119 pub fn to_value(self) -> Value {
120 Value::ByVal(self.primval)
124 impl ::std::convert::From<PrimVal> for Pointer {
125 fn from(primval: PrimVal) -> Self {
130 impl ::std::convert::From<MemoryPointer> for Pointer {
131 fn from(ptr: MemoryPointer) -> Self {
132 PrimVal::Ptr(ptr).into()
136 /// A `PrimVal` represents an immediate, primitive value existing outside of a
137 /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
138 /// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes
139 /// of a simple value, a pointer into another `Allocation`, or be undefined.
140 #[derive(Clone, Copy, Debug)]
142 /// The raw bytes of a simple value.
145 /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
146 /// relocations, but a `PrimVal` is only large enough to contain one, so we just represent the
147 /// relocation and its associated offset together as a `MemoryPointer` here.
150 /// An undefined `PrimVal`, for representing values that aren't safe to examine, but are safe
151 /// to copy around, just like undefined bytes in an `Allocation`.
155 #[derive(Clone, Copy, Debug, PartialEq)]
156 pub enum PrimValKind {
157 I8, I16, I32, I64, I128,
158 U8, U16, U32, U64, U128,
166 impl<'a, 'tcx: 'a> Value {
168 pub fn by_ref(ptr: Pointer) -> Self {
169 Value::ByRef { ptr, aligned: true }
172 /// Convert the value into a pointer (or a pointer-sized integer). If the value is a ByRef,
173 /// this may have to perform a load.
174 pub fn into_ptr<M: Machine<'tcx>>(&self, mem: &Memory<'a, 'tcx, M>) -> EvalResult<'tcx, Pointer> {
177 ByRef { ptr, aligned } => {
178 mem.read_maybe_aligned(aligned, |mem| mem.read_ptr(ptr.to_ptr()?) )
180 ByVal(ptr) | ByValPair(ptr, _) => Ok(ptr.into()),
184 pub(super) fn into_ptr_vtable_pair<M: Machine<'tcx>>(
186 mem: &Memory<'a, 'tcx, M>
187 ) -> EvalResult<'tcx, (Pointer, MemoryPointer)> {
190 ByRef { ptr: ref_ptr, aligned } => {
191 mem.read_maybe_aligned(aligned, |mem| {
192 let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?;
193 let vtable = mem.read_ptr(ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?)?;
194 Ok((ptr, vtable.to_ptr()?))
198 ByValPair(ptr, vtable) => Ok((ptr.into(), vtable.to_ptr()?)),
200 _ => bug!("expected ptr and vtable, got {:?}", self),
204 pub(super) fn into_slice<M: Machine<'tcx>>(&self, mem: &Memory<'a, 'tcx, M>) -> EvalResult<'tcx, (Pointer, u64)> {
207 ByRef { ptr: ref_ptr, aligned } => {
208 mem.read_maybe_aligned(aligned, |mem| {
209 let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?;
210 let len = mem.read_usize(ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?)?;
214 ByValPair(ptr, val) => {
215 let len = val.to_u128()?;
216 assert_eq!(len as u64 as u128, len);
217 Ok((ptr.into(), len as u64))
219 ByVal(_) => bug!("expected ptr and length, got {:?}", self),
225 pub fn from_u128(n: u128) -> Self {
229 pub fn from_i128(n: i128) -> Self {
230 PrimVal::Bytes(n as u128)
233 pub fn from_f32(f: f32) -> Self {
234 PrimVal::Bytes(f32_to_bytes(f))
237 pub fn from_f64(f: f64) -> Self {
238 PrimVal::Bytes(f64_to_bytes(f))
241 pub fn from_bool(b: bool) -> Self {
242 PrimVal::Bytes(b as u128)
245 pub fn from_char(c: char) -> Self {
246 PrimVal::Bytes(c as u128)
249 pub fn to_bytes(self) -> EvalResult<'tcx, u128> {
251 PrimVal::Bytes(b) => Ok(b),
252 PrimVal::Ptr(_) => Err(EvalError::ReadPointerAsBytes),
253 PrimVal::Undef => Err(EvalError::ReadUndefBytes),
257 pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
259 PrimVal::Bytes(_) => Err(EvalError::ReadBytesAsPointer),
260 PrimVal::Ptr(p) => Ok(p),
261 PrimVal::Undef => Err(EvalError::ReadUndefBytes),
265 pub fn is_bytes(self) -> bool {
267 PrimVal::Bytes(_) => true,
272 pub fn is_ptr(self) -> bool {
274 PrimVal::Ptr(_) => true,
279 pub fn is_undef(self) -> bool {
281 PrimVal::Undef => true,
286 pub fn to_u128(self) -> EvalResult<'tcx, u128> {
290 pub fn to_u64(self) -> EvalResult<'tcx, u64> {
291 self.to_bytes().map(|b| {
292 assert_eq!(b as u64 as u128, b);
297 pub fn to_i32(self) -> EvalResult<'tcx, i32> {
298 self.to_bytes().map(|b| {
299 assert_eq!(b as i32 as u128, b);
304 pub fn to_i128(self) -> EvalResult<'tcx, i128> {
305 self.to_bytes().map(|b| b as i128)
308 pub fn to_i64(self) -> EvalResult<'tcx, i64> {
309 self.to_bytes().map(|b| {
310 assert_eq!(b as i64 as u128, b);
315 pub fn to_f32(self) -> EvalResult<'tcx, f32> {
316 self.to_bytes().map(bytes_to_f32)
319 pub fn to_f64(self) -> EvalResult<'tcx, f64> {
320 self.to_bytes().map(bytes_to_f64)
323 pub fn to_bool(self) -> EvalResult<'tcx, bool> {
324 match self.to_bytes()? {
327 _ => Err(EvalError::InvalidBool),
333 pub fn is_int(self) -> bool {
334 use self::PrimValKind::*;
336 I8 | I16 | I32 | I64 | I128 | U8 | U16 | U32 | U64 | U128 => true,
341 pub fn is_signed_int(self) -> bool {
342 use self::PrimValKind::*;
344 I8 | I16 | I32 | I64 | I128 => true,
349 pub fn is_float(self) -> bool {
350 use self::PrimValKind::*;
357 pub fn from_uint_size(size: u64) -> Self {
359 1 => PrimValKind::U8,
360 2 => PrimValKind::U16,
361 4 => PrimValKind::U32,
362 8 => PrimValKind::U64,
363 16 => PrimValKind::U128,
364 _ => bug!("can't make uint with size {}", size),
368 pub fn from_int_size(size: u64) -> Self {
370 1 => PrimValKind::I8,
371 2 => PrimValKind::I16,
372 4 => PrimValKind::I32,
373 8 => PrimValKind::I64,
374 16 => PrimValKind::I128,
375 _ => bug!("can't make int with size {}", size),
379 pub fn is_ptr(self) -> bool {
380 use self::PrimValKind::*;