]> git.lizzy.rs Git - rust.git/commitdiff
Get rid of the integer allocation
authorOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Mon, 19 Jun 2017 08:58:59 +0000 (10:58 +0200)
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>
Tue, 20 Jun 2017 12:28:18 +0000 (14:28 +0200)
16 files changed:
src/cast.rs
src/error.rs
src/eval_context.rs
src/lvalue.rs
src/memory.rs
src/operator.rs
src/step.rs
src/terminator/drop.rs
src/terminator/intrinsic.rs
src/terminator/mod.rs
src/traits.rs
src/value.rs
tests/compile-fail/cast_box_int_to_fn_ptr.rs
tests/compile-fail/cast_int_to_fn_ptr.rs
tests/compile-fail/null_pointer_deref.rs
tests/compile-fail/wild_pointer_deref.rs

index 413c9b6ba827b54f4ab713636f0bddac606c4f8b..aa24de944a7c0f52a1d267519a299f953ac1dfa4 100644 (file)
@@ -3,7 +3,6 @@
 
 use error::{EvalResult, EvalError};
 use eval_context::EvalContext;
-use memory::Pointer;
 use value::PrimVal;
 
 impl<'a, 'tcx> EvalContext<'a, 'tcx> {
@@ -24,7 +23,7 @@ pub(super) fn cast_primval(
 
             Bool | Char | U8 | U16 | U32 | U64 | U128 => self.cast_int(val.to_u128()?, dest_ty, false),
 
-            FnPtr | Ptr => self.cast_ptr(val.to_ptr()?, dest_ty),
+            FnPtr | Ptr => self.cast_ptr(val, dest_ty),
         }
     }
 
@@ -71,7 +70,7 @@ fn cast_int(&self, v: u128, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx
             TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)),
             TyChar => Err(EvalError::InvalidChar(v)),
 
-            TyRawPtr(_) => Ok(PrimVal::Ptr(Pointer::from_int(v as u64))),
+            TyRawPtr(_) => Ok(PrimVal::Bytes(v % (1 << self.memory.pointer_size()))),
 
             _ => Err(EvalError::Unimplemented(format!("int to {:?} cast", ty))),
         }
@@ -92,11 +91,11 @@ fn cast_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
         }
     }
 
-    fn cast_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
+    fn cast_ptr(&self, ptr: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
         use rustc::ty::TypeVariants::*;
         match ty.sty {
             TyRef(..) | TyRawPtr(_) | TyFnPtr(_) | TyInt(_) | TyUint(_) =>
-                Ok(PrimVal::Ptr(ptr)),
+                Ok(ptr),
             _ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
         }
     }
index 1a8ca2d03ca6c133fba2a8201ec9066c5ac17ea9..e7e446e93ad7c655064879f6067c573dd157226d 100644 (file)
@@ -22,6 +22,7 @@ pub enum EvalError<'tcx> {
         allocation_size: u64,
     },
     ReadPointerAsBytes,
+    ReadBytesAsPointer,
     InvalidPointerMath,
     ReadUndefBytes,
     DeadLocal,
@@ -81,6 +82,8 @@ fn description(&self) -> &str {
                 "pointer offset outside bounds of allocation",
             EvalError::ReadPointerAsBytes =>
                 "a raw memory access tried to access part of a pointer value as raw bytes",
+            EvalError::ReadBytesAsPointer =>
+                "a memory access tried to interpret some bytes as a pointer",
             EvalError::InvalidPointerMath =>
                 "attempted to do math or a comparison on pointers into different allocations",
             EvalError::ReadUndefBytes =>
index 3b21f96bde0ce58e379cfed743a78d5336cb9480..55a031b310a58a87d776d14440248c52ca7851e7 100644 (file)
@@ -66,7 +66,8 @@ pub struct Frame<'tcx> {
     pub return_to_block: StackPopCleanup,
 
     /// The location where the result of the current stack frame should be written to.
-    pub return_lvalue: Lvalue<'tcx>,
+    /// None if the function is a diverging function
+    pub return_lvalue: Option<Lvalue<'tcx>>,
 
     /// The list of locals for this stack frame, stored in order as
     /// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
@@ -266,7 +267,7 @@ pub fn push_stack_frame(
         instance: ty::Instance<'tcx>,
         span: codemap::Span,
         mir: &'tcx mir::Mir<'tcx>,
-        return_lvalue: Lvalue<'tcx>,
+        return_lvalue: Option<Lvalue<'tcx>>,
         return_to_block: StackPopCleanup,
     ) -> EvalResult<'tcx> {
         ::log_settings::settings().indentation += 1;
@@ -323,7 +324,7 @@ pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
         ::log_settings::settings().indentation -= 1;
         let frame = self.stack.pop().expect("tried to pop a stack frame, but there were none");
         match frame.return_to_block {
-            StackPopCleanup::MarkStatic(mutable) => if let Lvalue::Global(id) = frame.return_lvalue {
+            StackPopCleanup::MarkStatic(mutable) => if let Lvalue::Global(id) = frame.return_lvalue.expect("diverging static") {
                 let global_value = self.globals.get_mut(&id)
                     .expect("global should have been cached (static)");
                 match global_value.value {
@@ -389,13 +390,13 @@ pub fn assign_discr_and_fields<
         where J::IntoIter: ExactSizeIterator,
     {
         // FIXME(solson)
-        let dest_ptr = self.force_allocation(dest)?.to_ptr();
+        let dest_ptr = self.force_allocation(dest)?.to_ptr()?;
 
         let discr_dest = dest_ptr.offset(discr_offset, self.memory.layout)?;
         self.memory.write_uint(discr_dest, discr_val, discr_size)?;
 
         let dest = Lvalue::Ptr {
-            ptr: dest_ptr,
+            ptr: PrimVal::Ptr(dest_ptr),
             extra: LvalueExtra::DowncastVariant(variant_idx),
         };
 
@@ -481,7 +482,7 @@ pub(super) fn eval_rvalue_into_lvalue(
                 match *dest_layout {
                     Univariant { ref variant, .. } => {
                         if variant.packed {
-                            let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
+                            let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0.to_ptr()?;
                             self.memory.mark_packed(ptr, variant.stride().bytes());
                         }
                         self.assign_fields(dest, dest_ty, operands)?;
@@ -499,7 +500,7 @@ pub(super) fn eval_rvalue_into_lvalue(
                                 .to_u128_unchecked();
                             let discr_size = discr.size().bytes();
                             if variants[variant].packed {
-                                let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
+                                let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0.to_ptr()?;
                                 self.memory.mark_packed(ptr, variants[variant].stride().bytes());
                             }
 
@@ -541,7 +542,7 @@ pub(super) fn eval_rvalue_into_lvalue(
                     StructWrappedNullablePointer { nndiscr, ref nonnull, ref discrfield, .. } => {
                         if let mir::AggregateKind::Adt(_, variant, _, _) = **kind {
                             if nonnull.packed {
-                                let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0;
+                                let ptr = self.force_allocation(dest)?.to_ptr_and_extra().0.to_ptr()?;
                                 self.memory.mark_packed(ptr, nonnull.stride().bytes());
                             }
                             if nndiscr == variant as u64 {
@@ -554,7 +555,7 @@ pub(super) fn eval_rvalue_into_lvalue(
                                 let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
 
                                 // FIXME(solson)
-                                let dest = self.force_allocation(dest)?.to_ptr();
+                                let dest = self.force_allocation(dest)?.to_ptr()?;
 
                                 let dest = dest.offset(offset.bytes(), self.memory.layout)?;
                                 let dest_size = self.type_size(ty)?
@@ -613,7 +614,7 @@ pub(super) fn eval_rvalue_into_lvalue(
                 let value = self.eval_operand(operand)?;
 
                 // FIXME(solson)
-                let dest = self.force_allocation(dest)?.to_ptr();
+                let dest = self.force_allocation(dest)?.to_ptr()?;
 
                 for i in 0..length {
                     let elem_dest = dest.offset(i * elem_size, self.memory.layout)?;
@@ -630,8 +631,7 @@ pub(super) fn eval_rvalue_into_lvalue(
 
             Ref(_, _, ref lvalue) => {
                 let src = self.eval_lvalue(lvalue)?;
-                let (raw_ptr, extra) = self.force_allocation(src)?.to_ptr_and_extra();
-                let ptr = PrimVal::Ptr(raw_ptr);
+                let (ptr, extra) = self.force_allocation(src)?.to_ptr_and_extra();
 
                 let val = match extra {
                     LvalueExtra::None => Value::ByVal(ptr),
@@ -726,7 +726,7 @@ pub(super) fn eval_rvalue_into_lvalue(
             Discriminant(ref lvalue) => {
                 let lval = self.eval_lvalue(lvalue)?;
                 let ty = self.lvalue_ty(lvalue);
-                let ptr = self.force_allocation(lval)?.to_ptr();
+                let ptr = self.force_allocation(lval)?.to_ptr()?;
                 let discr_val = self.read_discriminant_value(ptr, ty)?;
                 if let ty::TyAdt(adt_def, _) = ty.sty {
                     if adt_def.discriminants(self.tcx).all(|v| discr_val != v.to_u128_unchecked()) {
@@ -856,14 +856,14 @@ pub fn get_field_count(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, usize> {
         }
     }
 
-    pub(super) fn wrapping_pointer_offset(&self, ptr: Pointer, pointee_ty: Ty<'tcx>, offset: i64) -> EvalResult<'tcx, Pointer> {
+    pub(super) fn wrapping_pointer_offset(&self, ptr: PrimVal, pointee_ty: Ty<'tcx>, offset: i64) -> EvalResult<'tcx, PrimVal> {
         // FIXME: assuming here that type size is < i64::max_value()
         let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
         let offset = offset.overflowing_mul(pointee_size).0;
-        Ok(ptr.wrapping_signed_offset(offset, self.memory.layout))
+        ptr.wrapping_signed_offset(offset, self.memory.layout)
     }
 
-    pub(super) fn pointer_offset(&self, ptr: Pointer, pointee_ty: Ty<'tcx>, offset: i64) -> EvalResult<'tcx, Pointer> {
+    pub(super) fn pointer_offset(&self, ptr: PrimVal, pointee_ty: Ty<'tcx>, offset: i64) -> EvalResult<'tcx, PrimVal> {
         if offset == 0 {
             // rustc relies on Offset-by-0 to be well-defined even for "bad" pointers like Unique::empty().
             return Ok(ptr);
@@ -872,7 +872,7 @@ pub(super) fn pointer_offset(&self, ptr: Pointer, pointee_ty: Ty<'tcx>, offset:
         let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
         return if let Some(offset) = offset.checked_mul(pointee_size) {
             let ptr = ptr.signed_offset(offset, self.memory.layout)?;
-            self.memory.check_bounds(ptr, false)?;
+            self.memory.check_bounds(ptr.to_ptr()?, false)?;
             Ok(ptr)
         } else {
             Err(EvalError::OverflowingMath)
@@ -1036,7 +1036,7 @@ pub(super) fn write_value(
 
             Lvalue::Ptr { ptr, extra } => {
                 assert_eq!(extra, LvalueExtra::None);
-                self.write_value_to_ptr(src_val, ptr, dest_ty)
+                self.write_value_to_ptr(src_val, ptr.to_ptr()?, dest_ty)
             }
 
             Lvalue::Local { frame, local, field } => {
@@ -1242,20 +1242,20 @@ pub(super) fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'t
         }
     }
 
-    fn read_ptr(&mut self, ptr: Pointer, pointee_ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+    pub(crate) fn read_ptr(&self, ptr: Pointer, pointee_ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
         let p = self.memory.read_ptr(ptr)?;
         if self.type_is_sized(pointee_ty) {
-            Ok(Value::ByVal(PrimVal::Ptr(p)))
+            Ok(Value::ByVal(p))
         } else {
             trace!("reading fat pointer extra of type {}", pointee_ty);
             let extra = ptr.offset(self.memory.pointer_size(), self.memory.layout)?;
             let extra = match self.tcx.struct_tail(pointee_ty).sty {
-                ty::TyDynamic(..) => PrimVal::Ptr(self.memory.read_ptr(extra)?),
+                ty::TyDynamic(..) => self.memory.read_ptr(extra)?,
                 ty::TySlice(..) |
                 ty::TyStr => PrimVal::from_u128(self.memory.read_usize(extra)? as u128),
                 _ => bug!("unsized primval ptr read from {:?}", pointee_ty),
             };
-            Ok(Value::ByValPair(PrimVal::Ptr(p), extra))
+            Ok(Value::ByValPair(p, extra))
         }
     }
 
@@ -1301,7 +1301,7 @@ fn try_read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Opt
             ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr)?),
             ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr)?),
 
-            ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::Ptr)?,
+            ty::TyFnPtr(_) => self.memory.read_ptr(ptr)?,
             ty::TyRef(_, ref tam) |
             ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, tam.ty).map(Some),
 
@@ -1360,7 +1360,6 @@ fn unsize_into_ptr(
             (&ty::TyArray(_, length), &ty::TySlice(_)) => {
                 let ptr = src.read_ptr(&self.memory)?;
                 let len = PrimVal::from_u128(length as u128);
-                let ptr = PrimVal::Ptr(ptr);
                 self.write_value(Value::ByValPair(ptr, len), dest, dest_ty)
             }
             (&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
@@ -1374,7 +1373,6 @@ fn unsize_into_ptr(
                 let trait_ref = self.tcx.erase_regions(&trait_ref);
                 let vtable = self.get_vtable(src_pointee_ty, trait_ref)?;
                 let ptr = src.read_ptr(&self.memory)?;
-                let ptr = PrimVal::Ptr(ptr);
                 let extra = PrimVal::Ptr(vtable);
                 self.write_value(Value::ByValPair(ptr, extra), dest, dest_ty)
             },
@@ -1423,7 +1421,7 @@ fn unsize_into(
                 };
 
                 // FIXME(solson)
-                let dest = self.force_allocation(dest)?.to_ptr();
+                let dest = self.force_allocation(dest)?.to_ptr()?;
                 let iter = src_fields.zip(dst_fields).enumerate();
                 for (i, (src_f, dst_f)) in iter {
                     let src_fty = monomorphize_field_ty(self.tcx, src_f, substs_a);
@@ -1632,7 +1630,7 @@ fn run_main<'a, 'tcx: 'a>(
                 start_instance,
                 start_mir.span,
                 start_mir,
-                Lvalue::from_ptr(ret_ptr),
+                Some(Lvalue::from_ptr(ret_ptr)),
                 StackPopCleanup::None,
             )?;
 
@@ -1659,7 +1657,7 @@ fn run_main<'a, 'tcx: 'a>(
                 main_instance,
                 main_mir.span,
                 main_mir,
-                Lvalue::from_ptr(Pointer::zst_ptr()),
+                Some(Lvalue::zst()),
                 StackPopCleanup::None,
             )?;
         }
index c5811774e941e653797393b84d2d3b59f5bc620e..b61c18274aeb05adba0c13ecd72194e878d7a838 100644 (file)
 pub enum Lvalue<'tcx> {
     /// An lvalue referring to a value allocated in the `Memory` system.
     Ptr {
-        ptr: Pointer,
+        /// An lvalue may have an invalid (integral or undef) pointer,
+        /// since it might be turned back into a reference
+        /// before ever being dereferenced.
+        ptr: PrimVal,
         extra: LvalueExtra,
     },
 
@@ -61,11 +64,15 @@ pub struct Global<'tcx> {
 }
 
 impl<'tcx> Lvalue<'tcx> {
+    pub fn zst() -> Self {
+        Self::from_ptr(Pointer::zst_ptr())
+    }
+
     pub fn from_ptr(ptr: Pointer) -> Self {
-        Lvalue::Ptr { ptr, extra: LvalueExtra::None }
+        Lvalue::Ptr { ptr: PrimVal::Ptr(ptr), extra: LvalueExtra::None }
     }
 
-    pub(super) fn to_ptr_and_extra(self) -> (Pointer, LvalueExtra) {
+    pub(super) fn to_ptr_and_extra(self) -> (PrimVal, LvalueExtra) {
         match self {
             Lvalue::Ptr { ptr, extra } => (ptr, extra),
             _ => bug!("to_ptr_and_extra: expected Lvalue::Ptr, got {:?}", self),
@@ -73,10 +80,10 @@ pub(super) fn to_ptr_and_extra(self) -> (Pointer, LvalueExtra) {
         }
     }
 
-    pub(super) fn to_ptr(self) -> Pointer {
+    pub(super) fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
         let (ptr, extra) = self.to_ptr_and_extra();
         assert_eq!(extra, LvalueExtra::None);
-        ptr
+        ptr.to_ptr()
     }
 
     pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
@@ -127,7 +134,7 @@ pub(super) fn eval_and_read_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> Eva
         match lvalue {
             Lvalue::Ptr { ptr, extra } => {
                 assert_eq!(extra, LvalueExtra::None);
-                Ok(Value::ByRef(ptr))
+                Ok(Value::ByRef(ptr.to_ptr()?))
             }
             Lvalue::Local { frame, local, field } => {
                 self.stack[frame].get_local(local, field.map(|(i, _)| i))
@@ -141,7 +148,7 @@ pub(super) fn eval_and_read_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> Eva
     pub(super) fn eval_lvalue(&mut self, mir_lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue<'tcx>> {
         use rustc::mir::Lvalue::*;
         let lvalue = match *mir_lvalue {
-            Local(mir::RETURN_POINTER) => self.frame().return_lvalue,
+            Local(mir::RETURN_POINTER) => self.frame().return_lvalue.expect("diverging function returned"),
             Local(local) => Lvalue::Local { frame: self.stack.len() - 1, local, field: None },
 
             Static(ref static_) => {
@@ -229,14 +236,14 @@ pub fn lvalue_field(
             Lvalue::Local { frame, local, field } => match self.stack[frame].get_local(local, field.map(|(i, _)| i))? {
                 Value::ByRef(ptr) => {
                     assert!(field.is_none(), "local can't be ByRef and have a field offset");
-                    (ptr, LvalueExtra::None)
+                    (PrimVal::Ptr(ptr), LvalueExtra::None)
                 },
                 Value::ByVal(PrimVal::Undef) => {
                     // FIXME: allocate in fewer cases
                     if self.ty_to_primval_kind(base_ty).is_ok() {
                         return Ok(base);
                     } else {
-                        (self.force_allocation(base)?.to_ptr(), LvalueExtra::None)
+                        (PrimVal::Ptr(self.force_allocation(base)?.to_ptr()?), LvalueExtra::None)
                     }
                 },
                 Value::ByVal(_) => {
@@ -264,7 +271,7 @@ pub fn lvalue_field(
 
         let offset = match base_extra {
             LvalueExtra::Vtable(tab) => {
-                let (_, align) = self.size_and_align_of_dst(base_ty, Value::ByValPair(PrimVal::Ptr(base_ptr), PrimVal::Ptr(tab)))?;
+                let (_, align) = self.size_and_align_of_dst(base_ty, Value::ByValPair(base_ptr, PrimVal::Ptr(tab)))?;
                 offset.abi_align(Align::from_bytes(align, align).unwrap()).bytes()
             }
             _ => offset.bytes(),
@@ -276,7 +283,7 @@ pub fn lvalue_field(
 
         if packed {
             let size = self.type_size(field_ty)?.expect("packed struct must be sized");
-            self.memory.mark_packed(ptr, size);
+            self.memory.mark_packed(ptr.to_ptr()?, size);
         }
 
         let extra = if self.type_is_sized(field_ty) {
index f106f9d088c00d73741237857998e567aaa08f03..9e33a162b592374c780c3c952c3185702f73cd43 100644 (file)
@@ -6,7 +6,7 @@
 use rustc::ty::layout::{self, TargetDataLayout};
 
 use error::{EvalError, EvalResult};
-use value::PrimVal;
+use value::{PrimVal, self};
 
 ////////////////////////////////////////////////////////////////////////////////
 // Allocations and pointers
@@ -61,70 +61,31 @@ pub fn new(alloc_id: AllocId, offset: u64) -> Self {
     }
 
     pub fn wrapping_signed_offset<'tcx>(self, i: i64, layout: &TargetDataLayout) -> Self {
-        Pointer::new(self.alloc_id, (self.offset.wrapping_add(i as u64) as u128 % (1u128 << layout.pointer_size.bits())) as u64)
+        Pointer::new(self.alloc_id, value::wrapping_signed_offset(self.offset, i, layout))
     }
 
     pub fn signed_offset<'tcx>(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
-        // FIXME: is it possible to over/underflow here?
-        if i < 0 {
-            // trickery to ensure that i64::min_value() works fine
-            // this formula only works for true negative values, it panics for zero!
-            let n = u64::max_value() - (i as u64) + 1;
-            if let Some(res) = self.offset.checked_sub(n) {
-                Ok(Pointer::new(self.alloc_id, res))
-            } else {
-                Err(EvalError::OverflowingMath)
-            }
-        } else {
-            self.offset(i as u64, layout)
-        }
+        Ok(Pointer::new(self.alloc_id, value::signed_offset(self.offset, i, layout)?))
     }
 
     pub fn offset<'tcx>(self, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
-        if let Some(res) = self.offset.checked_add(i) {
-            if res as u128 >= (1u128 << layout.pointer_size.bits()) {
-                Err(EvalError::OverflowingMath)
-            } else {
-                Ok(Pointer::new(self.alloc_id, res))
-            }
-        } else {
-            Err(EvalError::OverflowingMath)
-        }
+        Ok(Pointer::new(self.alloc_id, value::offset(self.offset, i, layout)?))
     }
 
     pub fn points_to_zst(&self) -> bool {
         self.alloc_id == ZST_ALLOC_ID
     }
 
-    pub fn to_int<'tcx>(&self) -> EvalResult<'tcx, u64> {
-        match self.alloc_id {
-            NEVER_ALLOC_ID => Ok(self.offset),
-            _ => Err(EvalError::ReadPointerAsBytes),
-        }
-    }
-
-    pub fn from_int(i: u64) -> Self {
-        Pointer::new(NEVER_ALLOC_ID, i)
-    }
-
     pub fn zst_ptr() -> Self {
         Pointer::new(ZST_ALLOC_ID, 0)
     }
-
-    pub fn never_ptr() -> Self {
-        Pointer::new(NEVER_ALLOC_ID, 0)
-    }
-    
-    pub fn is_null_ptr(&self) -> bool {
-        return *self == Pointer::from_int(0)
-    }
 }
 
 pub type TlsKey = usize;
 
 #[derive(Copy, Clone, Debug)]
 pub struct TlsEntry<'tcx> {
-    data: Pointer, // Will eventually become a map from thread IDs to pointers, if we ever support more than one thread.
+    data: PrimVal, // Will eventually become a map from thread IDs to `PrimVal`s, if we ever support more than one thread.
     dtor: Option<ty::Instance<'tcx>>,
 }
 
@@ -187,7 +148,6 @@ pub struct Memory<'a, 'tcx> {
 }
 
 const ZST_ALLOC_ID: AllocId = AllocId(0);
-const NEVER_ALLOC_ID: AllocId = AllocId(1);
 
 impl<'a, 'tcx> Memory<'a, 'tcx> {
     pub fn new(layout: &'a TargetDataLayout, max_memory: u64) -> Self {
@@ -395,7 +355,7 @@ pub(crate) fn clear_packed(&mut self) {
     pub(crate) fn create_tls_key(&mut self, dtor: Option<ty::Instance<'tcx>>) -> TlsKey {
         let new_key = self.next_thread_local;
         self.next_thread_local += 1;
-        self.thread_local.insert(new_key, TlsEntry { data: Pointer::from_int(0), dtor });
+        self.thread_local.insert(new_key, TlsEntry { data: PrimVal::Bytes(0), dtor });
         trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor);
         return new_key;
     }
@@ -410,7 +370,7 @@ pub(crate) fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> {
         }
     }
 
-    pub(crate) fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer> {
+    pub(crate) fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, PrimVal> {
         return match self.thread_local.get(&key) {
             Some(&TlsEntry { data, .. }) => {
                 trace!("TLS key {} loaded: {:?}", key, data);
@@ -420,7 +380,7 @@ pub(crate) fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer> {
         }
     }
 
-    pub(crate) fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx> {
+    pub(crate) fn store_tls(&mut self, key: TlsKey, new_data: PrimVal) -> EvalResult<'tcx> {
         return match self.thread_local.get_mut(&key) {
             Some(&mut TlsEntry { ref mut data, .. }) => {
                 trace!("TLS key {} stored: {:?}", key, new_data);
@@ -431,14 +391,14 @@ pub(crate) fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult
         }
     }
     
-    // Returns a dtor and its argument, if one is supposed to run
-    pub(crate) fn fetch_tls_dtor(&mut self) -> Option<(ty::Instance<'tcx>, Pointer)> {
+    /// Returns a dtor and its argument, if one is supposed to run
+    pub(crate) fn fetch_tls_dtor(&mut self) -> Option<(ty::Instance<'tcx>, PrimVal)> {
         for (_, &mut TlsEntry { ref mut data, dtor }) in self.thread_local.iter_mut() {
-            if !data.is_null_ptr() {
+            if *data != PrimVal::Bytes(0) {
                 if let Some(dtor) = dtor {
-                    let old_data = *data;
-                    *data = Pointer::from_int(0);
-                    return Some((dtor, old_data));
+                    let ret = Some((dtor, *data));
+                    *data = PrimVal::Bytes(0);
+                    return ret;
                 }
             }
         }
@@ -467,7 +427,7 @@ pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
             Some(alloc) => Ok(alloc),
             None => match self.functions.get(&id) {
                 Some(_) => Err(EvalError::DerefFunctionPointer),
-                None if id == NEVER_ALLOC_ID || id == ZST_ALLOC_ID => Err(EvalError::InvalidMemoryAccess),
+                None if id == ZST_ALLOC_ID => Err(EvalError::InvalidMemoryAccess),
                 None => Err(EvalError::DanglingPointerDeref),
             }
         }
@@ -482,7 +442,7 @@ pub fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation> {
             },
             None => match self.functions.get(&id) {
                 Some(_) => Err(EvalError::DerefFunctionPointer),
-                None if id == NEVER_ALLOC_ID || id == ZST_ALLOC_ID => Err(EvalError::InvalidMemoryAccess),
+                None if id == ZST_ALLOC_ID => Err(EvalError::InvalidMemoryAccess),
                 None => Err(EvalError::DanglingPointerDeref),
             }
         }
@@ -513,7 +473,7 @@ pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) {
         let mut allocs_seen = HashSet::new();
 
         while let Some(id) = allocs_to_print.pop_front() {
-            if id == ZST_ALLOC_ID || id == NEVER_ALLOC_ID { continue; }
+            if id == ZST_ALLOC_ID { continue; }
             let mut msg = format!("Alloc {:<5} ", format!("{}:", id));
             let prefix_len = msg.len();
             let mut relocations = vec![];
@@ -563,7 +523,6 @@ pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) {
                     write!(msg, "{:1$}", "", ((i - pos) * 3) as usize).unwrap();
                     let target = match target_id {
                         ZST_ALLOC_ID => String::from("zst"),
-                        NEVER_ALLOC_ID => String::from("int ptr"),
                         _ => format!("({})", target_id),
                     };
                     // this `as usize` is fine, since we can't print more chars than `usize::MAX`
@@ -647,7 +606,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
     /// mark an allocation as being the entry point to a static (see `static_alloc` field)
     pub fn mark_static(&mut self, alloc_id: AllocId) {
         trace!("mark_static: {:?}", alloc_id);
-        if alloc_id != NEVER_ALLOC_ID && alloc_id != ZST_ALLOC_ID && !self.static_alloc.insert(alloc_id) {
+        if alloc_id != ZST_ALLOC_ID && !self.static_alloc.insert(alloc_id) {
             bug!("tried to mark an allocation ({:?}) as static twice", alloc_id);
         }
     }
@@ -677,7 +636,7 @@ pub fn mark_static_initalized(&mut self, alloc_id: AllocId, mutable: bool) -> Ev
                 // mark recursively
                 mem::replace(relocations, Default::default())
             },
-            None if alloc_id == NEVER_ALLOC_ID || alloc_id == ZST_ALLOC_ID => return Ok(()),
+            None if alloc_id == ZST_ALLOC_ID => return Ok(()),
             None if !self.functions.contains_key(&alloc_id) => return Err(EvalError::DanglingPointerDeref),
             _ => return Ok(()),
         };
@@ -749,9 +708,11 @@ pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: u64) -> EvalResult<
         Ok(())
     }
 
-    pub fn read_ptr(&self, ptr: Pointer) -> EvalResult<'tcx, Pointer> {
+    pub fn read_ptr(&self, ptr: Pointer) -> EvalResult<'tcx, PrimVal> {
         let size = self.pointer_size();
-        self.check_defined(ptr, size)?;
+        if self.check_defined(ptr, size).is_err() {
+            return Ok(PrimVal::Undef);
+        }
         let endianess = self.endianess();
         let bytes = self.get_bytes_unchecked(ptr, size, size)?;
         let offset = read_target_uint(endianess, bytes).unwrap();
@@ -759,16 +720,14 @@ pub fn read_ptr(&self, ptr: Pointer) -> EvalResult<'tcx, Pointer> {
         let offset = offset as u64;
         let alloc = self.get(ptr.alloc_id)?;
         match alloc.relocations.get(&ptr.offset) {
-            Some(&alloc_id) => Ok(Pointer::new(alloc_id, offset)),
-            None => Ok(Pointer::from_int(offset)),
+            Some(&alloc_id) => Ok(PrimVal::Ptr(Pointer::new(alloc_id, offset))),
+            None => Ok(PrimVal::Bytes(offset as u128)),
         }
     }
 
     pub fn write_ptr(&mut self, dest: Pointer, ptr: Pointer) -> EvalResult<'tcx> {
         self.write_usize(dest, ptr.offset as u64)?;
-        if ptr.alloc_id != NEVER_ALLOC_ID {
-            self.get_mut(dest.alloc_id)?.relocations.insert(dest.offset, ptr.alloc_id);
-        }
+        self.get_mut(dest.alloc_id)?.relocations.insert(dest.offset, ptr.alloc_id);
         Ok(())
     }
 
index 3fe3b63407910eb2b531aaeaed60c4d6229685b4..0303fbe1f79f62ac11cbcc89dbfd02f7efb46d77 100644 (file)
@@ -4,7 +4,6 @@
 use error::{EvalError, EvalResult};
 use eval_context::EvalContext;
 use lvalue::Lvalue;
-use memory::Pointer;
 use value::{
     PrimVal,
     PrimValKind,
@@ -73,6 +72,7 @@ macro_rules! int_arithmetic {
     ($kind:expr, $int_op:ident, $l:expr, $r:expr) => ({
         let l = $l;
         let r = $r;
+        use value::PrimValKind::*;
         match $kind {
             I8  => overflow!($int_op, l as i8,  r as i8),
             I16 => overflow!($int_op, l as i16, r as i16),
@@ -143,18 +143,6 @@ pub fn binary_op(
         use rustc::mir::BinOp::*;
         use value::PrimValKind::*;
 
-        // FIXME(solson): Temporary hack. It will go away when we get rid of Pointer's ability to store
-        // plain bytes, and leave that to PrimVal::Bytes.
-        fn normalize(val: PrimVal) -> PrimVal {
-            if let PrimVal::Ptr(ptr) = val {
-                if let Ok(bytes) = ptr.to_int() {
-                    return PrimVal::Bytes(bytes as u128);
-                }
-            }
-            val
-        }
-        let (left, right) = (normalize(left), normalize(right));
-
         let left_kind  = self.ty_to_primval_kind(left_ty)?;
         let right_kind = self.ty_to_primval_kind(right_ty)?;
 
@@ -162,29 +150,43 @@ fn normalize(val: PrimVal) -> PrimVal {
         if bin_op == Offset {
             if left_kind == Ptr && right_kind == PrimValKind::from_uint_size(self.memory.pointer_size()) {
                 let pointee_ty = left_ty.builtin_deref(true, ty::LvaluePreference::NoPreference).expect("Offset called on non-ptr type").ty;
-                let ptr = self.pointer_offset(left.to_ptr()?, pointee_ty, right.to_bytes()? as i64)?;
-                return Ok((PrimVal::Ptr(ptr), false));
+                let ptr = self.pointer_offset(left, pointee_ty, right.to_bytes()? as i64)?;
+                return Ok((ptr, false));
             } else {
                 bug!("Offset used with wrong type");
             }
         }
 
-        let (l, r) = match (left, right) {
-            (PrimVal::Bytes(left_bytes), PrimVal::Bytes(right_bytes)) => (left_bytes, right_bytes),
-
-            // One argument is a pointer value -- this is handled separately
-            (PrimVal::Ptr(left_ptr), PrimVal::Ptr(right_ptr)) => {
-                return self.ptr_ops(bin_op, left_ptr, left_kind, right_ptr, right_kind);
-            }
-            (PrimVal::Ptr(ptr), PrimVal::Bytes(bytes)) => {
-                return self.ptr_ops(bin_op, ptr, left_kind, Pointer::from_int(bytes as u64), right_kind);
+        // unrelated pointer ops
+        let op: Option<fn(&PrimVal, &PrimVal) -> bool> = match bin_op {
+            Eq => Some(PrimVal::eq),
+            Ne => Some(PrimVal::ne),
+            _ => None,
+        };
+        if let Some(op) = op {
+            // only floats can't be binary compared
+            let ok = left_kind != F32 && left_kind != F64;
+            let ok = ok && right_kind != F32 && right_kind != F64;
+            if ok {
+                return Ok((PrimVal::from_bool(op(&left, &right)), false));
             }
-            (PrimVal::Bytes(bytes), PrimVal::Ptr(ptr)) => {
-                return self.ptr_ops(bin_op, Pointer::from_int(bytes as u64), left_kind, ptr, right_kind);
+        }
+
+        
+        if let (Ok(left), Ok(right)) = (left.to_ptr(), right.to_ptr()) {
+            if left.alloc_id == right.alloc_id {
+                return self.ptr_ops(
+                    bin_op,
+                    left.offset,
+                    right.offset,
+                );
+            } else {
+                return Err(EvalError::InvalidPointerMath);
             }
+        }
 
-            (PrimVal::Undef, _) | (_, PrimVal::Undef) => return Err(EvalError::ReadUndefBytes),
-        };
+        let l = left.to_bytes()?;
+        let r = right.to_bytes()?;
 
         // These ops can have an RHS with a different numeric type.
         if right_kind.is_int() && (bin_op == Shl || bin_op == Shr) {
@@ -260,41 +262,26 @@ fn normalize(val: PrimVal) -> PrimVal {
     fn ptr_ops(
         &self,
         bin_op: mir::BinOp,
-        left: Pointer,
-        left_kind: PrimValKind,
-        right: Pointer,
-        right_kind: PrimValKind,
+        left: u64,
+        right: u64,
     ) -> EvalResult<'tcx, (PrimVal, bool)> {
         use rustc::mir::BinOp::*;
-        use value::PrimValKind::*;
-
-        if left_kind != right_kind || !(left_kind.is_ptr() || left_kind == PrimValKind::from_uint_size(self.memory.pointer_size())) {
-            let msg = format!("unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, left, left_kind, right, right_kind);
-            return Err(EvalError::Unimplemented(msg));
-        }
 
         let val = match bin_op {
             Eq => PrimVal::from_bool(left == right),
             Ne => PrimVal::from_bool(left != right),
             Lt | Le | Gt | Ge => {
-                if left.alloc_id == right.alloc_id {
-                    PrimVal::from_bool(match bin_op {
-                        Lt => left.offset < right.offset,
-                        Le => left.offset <= right.offset,
-                        Gt => left.offset > right.offset,
-                        Ge => left.offset >= right.offset,
-                        _ => bug!("We already established it has to be a comparison operator."),
-                    })
-                } else {
-                    return Err(EvalError::InvalidPointerMath);
-                }
+                PrimVal::from_bool(match bin_op {
+                    Lt => left < right,
+                    Le => left <= right,
+                    Gt => left > right,
+                    Ge => left >= right,
+                    _ => bug!("We already established it has to be a comparison operator."),
+                })
             }
             Sub => {
-                if left.alloc_id == right.alloc_id {
-                    return int_arithmetic!(left_kind, overflowing_sub, left.offset, right.offset);
-                } else {
-                    return Err(EvalError::InvalidPointerMath);
-                }
+                let usize = PrimValKind::from_uint_size(self.memory.pointer_size());
+                return int_arithmetic!(usize, overflowing_sub, left, right);
             }
             _ => {
                 return Err(EvalError::ReadPointerAsBytes);
index eaf3069a907e0d77a3c31b21065f48e94eb0113a..0fd3f0b3a43ed5325c68f14fd128277d67f3c14a 100644 (file)
@@ -14,7 +14,6 @@
 use eval_context::{EvalContext, StackPopCleanup};
 use lvalue::{Global, GlobalId, Lvalue};
 use value::{Value, PrimVal};
-use memory::Pointer;
 use syntax::codemap::Span;
 
 impl<'a, 'tcx> EvalContext<'a, 'tcx> {
@@ -41,13 +40,13 @@ pub fn step(&mut self) -> EvalResult<'tcx, bool> {
                     instance,
                     mir.span,
                     mir,
-                    Lvalue::from_ptr(Pointer::zst_ptr()),
+                    Some(Lvalue::zst()),
                     StackPopCleanup::None,
                 )?;
                 let arg_local = self.frame().mir.args_iter().next().ok_or(EvalError::AbiViolation("TLS dtor does not take enough arguments.".to_owned()))?;
                 let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
                 let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8);
-                self.write_value(Value::ByVal(PrimVal::Ptr(ptr)), dest, ty)?;
+                self.write_primval(dest, ptr, ty)?;
                 return Ok(true);
             }
             return Ok(false);
@@ -192,7 +191,7 @@ fn global_item(
         }
         if self.ecx.tcx.has_attr(def_id, "linkage") {
             trace!("Initializing an extern global with NULL");
-            self.ecx.globals.insert(cid, Global::initialized(self.ecx.tcx.type_of(def_id), Value::ByVal(PrimVal::Ptr(Pointer::from_int(0))), !shared));
+            self.ecx.globals.insert(cid, Global::initialized(self.ecx.tcx.type_of(def_id), Value::ByVal(PrimVal::Bytes(0)), !shared));
             return;
         }
         self.try(|this| {
@@ -210,7 +209,7 @@ fn global_item(
                 instance,
                 span,
                 mir,
-                Lvalue::Global(cid),
+                Some(Lvalue::Global(cid)),
                 cleanup,
             )
         });
@@ -253,7 +252,7 @@ fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Loca
                     this.ecx.push_stack_frame(this.instance,
                                               constant.span,
                                               mir,
-                                              Lvalue::Global(cid),
+                                              Some(Lvalue::Global(cid)),
                                               StackPopCleanup::MarkStatic(false),
                     )
                 });
index 776061954251c59c5f1467aa5df47edf2ce09d7e..463d9b3388b53b2916ab0b0e844ef7137592866e 100644 (file)
@@ -5,7 +5,6 @@
 use error::EvalResult;
 use eval_context::{EvalContext, StackPopCleanup};
 use lvalue::{Lvalue, LvalueExtra};
-use memory::Pointer;
 use value::PrimVal;
 use value::Value;
 
@@ -13,9 +12,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
     pub(crate) fn drop_lvalue(&mut self, lval: Lvalue<'tcx>, instance: ty::Instance<'tcx>, ty: Ty<'tcx>, span: Span) -> EvalResult<'tcx> {
         trace!("drop_lvalue: {:#?}", lval);
         let val = match self.force_allocation(lval)? {
-            Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable) } => Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Ptr(vtable)),
-            Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len) } => Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len as u128)),
-            Lvalue::Ptr { ptr, extra: LvalueExtra::None } => Value::ByVal(PrimVal::Ptr(ptr)),
+            Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable) } => Value::ByValPair(ptr, PrimVal::Ptr(vtable)),
+            Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len) } => Value::ByValPair(ptr, PrimVal::Bytes(len as u128)),
+            Lvalue::Ptr { ptr, extra: LvalueExtra::None } => Value::ByVal(ptr),
             _ => bug!("force_allocation broken"),
         };
         self.drop(val, instance, ty, span)
@@ -50,7 +49,7 @@ pub(crate) fn drop(&mut self, arg: Value, mut instance: ty::Instance<'tcx>, ty:
             instance,
             span,
             mir,
-            Lvalue::from_ptr(Pointer::zst_ptr()),
+            Some(Lvalue::zst()),
             StackPopCleanup::None,
         )?;
 
index ce3216f00153a8c74a494fb14a58e283549cfa3f..a69380f1b18da9f9fecc82619044531e2f4b19a8 100644 (file)
@@ -46,7 +46,7 @@ pub(super) fn call_intrinsic(
                 let offset = self.value_to_primval(arg_vals[1], isize)?.to_i128()? as i64;
                 let ptr = arg_vals[0].read_ptr(&self.memory)?;
                 let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?;
-                self.write_primval(dest, PrimVal::Ptr(result_ptr), dest_ty)?;
+                self.write_primval(dest, result_ptr, dest_ty)?;
             }
 
             "assume" => {
@@ -60,7 +60,7 @@ pub(super) fn call_intrinsic(
             "atomic_load_acq" |
             "volatile_load" => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].read_ptr(&self.memory)?;
+                let ptr = arg_vals[0].read_ptr(&self.memory)?.to_ptr()?;
                 self.write_value(Value::ByRef(ptr), dest, ty)?;
             }
 
@@ -69,7 +69,7 @@ pub(super) fn call_intrinsic(
             "atomic_store_rel" |
             "volatile_store" => {
                 let ty = substs.type_at(0);
-                let dest = arg_vals[0].read_ptr(&self.memory)?;
+                let dest = arg_vals[0].read_ptr(&self.memory)?.to_ptr()?;
                 self.write_value_to_ptr(arg_vals[1], dest, ty)?;
             }
 
@@ -79,7 +79,7 @@ pub(super) fn call_intrinsic(
 
             _ if intrinsic_name.starts_with("atomic_xchg") => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].read_ptr(&self.memory)?;
+                let ptr = arg_vals[0].read_ptr(&self.memory)?.to_ptr()?;
                 let change = self.value_to_primval(arg_vals[1], ty)?;
                 let old = self.read_value(ptr, ty)?;
                 let old = match old {
@@ -93,7 +93,7 @@ pub(super) fn call_intrinsic(
 
             _ if intrinsic_name.starts_with("atomic_cxchg") => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].read_ptr(&self.memory)?;
+                let ptr = arg_vals[0].read_ptr(&self.memory)?.to_ptr()?;
                 let expect_old = self.value_to_primval(arg_vals[1], ty)?;
                 let change = self.value_to_primval(arg_vals[2], ty)?;
                 let old = self.read_value(ptr, ty)?;
@@ -103,7 +103,7 @@ pub(super) fn call_intrinsic(
                     Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"),
                 };
                 let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?;
-                let dest = self.force_allocation(dest)?.to_ptr();
+                let dest = self.force_allocation(dest)?.to_ptr()?;
                 self.write_pair_to_ptr(old, val, dest, dest_ty)?;
                 self.write_primval(Lvalue::from_ptr(ptr), change, ty)?;
             }
@@ -114,7 +114,7 @@ pub(super) fn call_intrinsic(
             "atomic_xadd" | "atomic_xadd_acq" | "atomic_xadd_rel" | "atomic_xadd_acqrel" | "atomic_xadd_relaxed" |
             "atomic_xsub" | "atomic_xsub_acq" | "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].read_ptr(&self.memory)?;
+                let ptr = arg_vals[0].read_ptr(&self.memory)?.to_ptr()?;
                 let change = self.value_to_primval(arg_vals[1], ty)?;
                 let old = self.read_value(ptr, ty)?;
                 let old = match old {
@@ -143,11 +143,13 @@ pub(super) fn call_intrinsic(
                 // FIXME: check whether overlapping occurs
                 let elem_ty = substs.type_at(0);
                 let elem_size = self.type_size(elem_ty)?.expect("cannot copy unsized value");
-                let elem_align = self.type_align(elem_ty)?;
-                let src = arg_vals[0].read_ptr(&self.memory)?;
-                let dest = arg_vals[1].read_ptr(&self.memory)?;
-                let count = self.value_to_primval(arg_vals[2], usize)?.to_u64()?;
-                self.memory.copy(src, dest, count * elem_size, elem_align)?;
+                if elem_size != 0 {
+                    let elem_align = self.type_align(elem_ty)?;
+                    let src = arg_vals[0].read_ptr(&self.memory)?.to_ptr()?;
+                    let dest = arg_vals[1].read_ptr(&self.memory)?.to_ptr()?;
+                    let count = self.value_to_primval(arg_vals[2], usize)?.to_u64()?;
+                    self.memory.copy(src, dest, count * elem_size, elem_align)?;
+                }
             }
 
             "ctpop" |
@@ -163,7 +165,7 @@ pub(super) fn call_intrinsic(
 
             "discriminant_value" => {
                 let ty = substs.type_at(0);
-                let adt_ptr = arg_vals[0].read_ptr(&self.memory)?;
+                let adt_ptr = arg_vals[0].read_ptr(&self.memory)?.to_ptr()?;
                 let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
                 self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
             }
@@ -259,7 +261,7 @@ pub(super) fn call_intrinsic(
                 };
                 match dest {
                     Lvalue::Local { frame, local, field } => self.modify_local(frame, local, field.map(|(i, _)| i), init)?,
-                    Lvalue::Ptr { ptr, extra: LvalueExtra::None } => self.memory.write_repeat(ptr, 0, size)?,
+                    Lvalue::Ptr { ptr, extra: LvalueExtra::None } => self.memory.write_repeat(ptr.to_ptr()?, 0, size)?,
                     Lvalue::Ptr { .. } => bug!("init intrinsic tried to write to fat ptr target"),
                     Lvalue::Global(cid) => self.modify_global(cid, init)?,
                 }
@@ -282,7 +284,7 @@ pub(super) fn call_intrinsic(
 
             "move_val_init" => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].read_ptr(&self.memory)?;
+                let ptr = arg_vals[0].read_ptr(&self.memory)?.to_ptr()?;
                 self.write_value_to_ptr(arg_vals[1], ptr, ty)?;
             }
 
@@ -297,7 +299,7 @@ pub(super) fn call_intrinsic(
                 let offset = self.value_to_primval(arg_vals[1], isize)?.to_i128()? as i64;
                 let ptr = arg_vals[0].read_ptr(&self.memory)?;
                 let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?;
-                self.write_primval(dest, PrimVal::Ptr(result_ptr), dest_ty)?;
+                self.write_primval(dest, result_ptr, dest_ty)?;
             }
 
             "overflowing_sub" => {
@@ -388,7 +390,7 @@ pub(super) fn call_intrinsic(
                 let dest_align = self.type_align(dest_ty)?;
                 let size = self.type_size(dest_ty)?.expect("transmute() type must be sized");
                 if dest_align < src_align {
-                    let ptr = self.force_allocation(dest)?.to_ptr();
+                    let ptr = self.force_allocation(dest)?.to_ptr()?;
                     self.memory.mark_packed(ptr, size);
                     self.write_value_to_ptr(arg_vals[0], ptr, dest_ty)?;
                 } else {
@@ -410,7 +412,7 @@ pub(super) fn call_intrinsic(
                 match dest {
                     Lvalue::Local { frame, local, field } => self.modify_local(frame, local, field.map(|(i, _)| i), uninit)?,
                     Lvalue::Ptr { ptr, extra: LvalueExtra::None } =>
-                        self.memory.mark_definedness(ptr, size, false)?,
+                        self.memory.mark_definedness(ptr.to_ptr()?, size, false)?,
                     Lvalue::Ptr { .. } => bug!("uninit intrinsic tried to write to fat ptr target"),
                     Lvalue::Global(cid) => self.modify_global(cid, uninit)?,
                 }
@@ -422,7 +424,7 @@ pub(super) fn call_intrinsic(
                 let ty_align = self.type_align(ty)?;
                 let val_byte = self.value_to_primval(arg_vals[1], u8)?.to_u128()? as u8;
                 let size = self.type_size(ty)?.expect("write_bytes() type must be sized");
-                let ptr = arg_vals[0].read_ptr(&self.memory)?;
+                let ptr = arg_vals[0].read_ptr(&self.memory)?.to_ptr()?;
                 let count = self.value_to_primval(arg_vals[2], usize)?.to_u64()?;
                 if count > 0 {
                     self.memory.check_align(ptr, ty_align, size * count)?;
index afc3bf1c37feb421257a5d5835f4292441b2042c..b9182a532e40fe40c5b899ead4a8a0c669fa673c 100644 (file)
@@ -30,7 +30,7 @@ pub(super) fn eval_terminator(
         use rustc::mir::TerminatorKind::*;
         match terminator.kind {
             Return => {
-                self.dump_local(self.frame().return_lvalue);
+                self.dump_local(self.frame().return_lvalue.expect("diverging function returned"));
                 self.pop_stack_frame()?
             }
 
@@ -388,7 +388,7 @@ fn eval_fn_call(
                 let ptr_size = self.memory.pointer_size();
                 let (_, vtable) = self.eval_operand(&arg_operands[0])?.expect_ptr_vtable_pair(&self.memory)?;
                 let fn_ptr = self.memory.read_ptr(vtable.offset(ptr_size * (idx as u64 + 3), self.memory.layout)?)?;
-                let instance = self.memory.get_fn(fn_ptr.alloc_id)?;
+                let instance = self.memory.get_fn(fn_ptr.to_ptr()?.alloc_id)?;
                 let mut arg_operands = arg_operands.to_vec();
                 let ty = self.operand_ty(&arg_operands[0]);
                 let ty = self.get_field_ty(ty, 0)?;
@@ -430,12 +430,8 @@ fn eval_fn_call_inner(
             Err(other) => return Err(other),
         };
         let (return_lvalue, return_to_block) = match destination {
-            Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)),
-            None => {
-                // FIXME(solson)
-                let lvalue = Lvalue::from_ptr(Pointer::never_ptr());
-                (lvalue, StackPopCleanup::None)
-            }
+            Some((lvalue, block)) => (Some(lvalue), StackPopCleanup::Goto(block)),
+            None => (None, StackPopCleanup::None),
         };
 
         self.push_stack_frame(
@@ -579,7 +575,7 @@ fn call_c_abi(
             }
 
             "__rust_deallocate" => {
-                let ptr = args[0].read_ptr(&self.memory)?;
+                let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
                 // FIXME: insert sanity check for size and align?
                 let _old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
                 let _align = self.value_to_primval(args[2], usize)?.to_u64()?;
@@ -587,7 +583,7 @@ fn call_c_abi(
             },
 
             "__rust_reallocate" => {
-                let ptr = args[0].read_ptr(&self.memory)?;
+                let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
                 let size = self.value_to_primval(args[2], usize)?.to_u64()?;
                 let align = self.value_to_primval(args[3], usize)?.to_u64()?;
                 let new_ptr = self.memory.reallocate(ptr, size, align)?;
@@ -598,7 +594,7 @@ fn call_c_abi(
                 // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32
                 // We abort on panic, so not much is going on here, but we still have to call the closure
                 let u8_ptr_ty = self.tcx.mk_mut_ptr(self.tcx.types.u8);
-                let f = args[0].read_ptr(&self.memory)?;
+                let f = args[0].read_ptr(&self.memory)?.to_ptr()?;
                 let data = args[1].read_ptr(&self.memory)?;
                 let f_instance = self.memory.get_fn(f.alloc_id)?;
                 self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
@@ -610,13 +606,13 @@ fn call_c_abi(
                     f_instance,
                     mir.span,
                     mir,
-                    Lvalue::from_ptr(Pointer::zst_ptr()),
+                    Some(Lvalue::zst()),
                     StackPopCleanup::Goto(dest_block),
                 )?;
 
                 let arg_local = self.frame().mir.args_iter().next().ok_or(EvalError::AbiViolation("Argument to __rust_maybe_catch_panic does not take enough arguments.".to_owned()))?;
                 let arg_dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
-                self.write_value(Value::ByVal(PrimVal::Ptr(data)), arg_dest, u8_ptr_ty)?;
+                self.write_primval(arg_dest, data, u8_ptr_ty)?;
 
                 // We ourselbes return 0
                 self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
@@ -630,8 +626,8 @@ fn call_c_abi(
             }
 
             "memcmp" => {
-                let left = args[0].read_ptr(&self.memory)?;
-                let right = args[1].read_ptr(&self.memory)?;
+                let left = args[0].read_ptr(&self.memory)?.to_ptr()?;
+                let right = args[1].read_ptr(&self.memory)?.to_ptr()?;
                 let n = self.value_to_primval(args[2], usize)?.to_u64()?;
 
                 let result = {
@@ -650,7 +646,7 @@ fn call_c_abi(
             }
 
             "memrchr" => {
-                let ptr = args[0].read_ptr(&self.memory)?;
+                let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
                 let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8;
                 let num = self.value_to_primval(args[2], usize)?.to_u64()?;
                 if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(|&c| c == val) {
@@ -662,7 +658,7 @@ fn call_c_abi(
             }
 
             "memchr" => {
-                let ptr = args[0].read_ptr(&self.memory)?;
+                let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
                 let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8;
                 let num = self.value_to_primval(args[2], usize)?.to_u64()?;
                 if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(|&c| c == val) {
@@ -675,7 +671,7 @@ fn call_c_abi(
 
             "getenv" => {
                 {
-                    let name_ptr = args[0].read_ptr(&self.memory)?;
+                    let name_ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
                     let name = self.memory.read_c_str(name_ptr)?;
                     info!("ignored env var request for `{:?}`", ::std::str::from_utf8(name));
                 }
@@ -684,7 +680,7 @@ fn call_c_abi(
 
             "write" => {
                 let fd = self.value_to_primval(args[0], usize)?.to_u64()?;
-                let buf = args[1].read_ptr(&self.memory)?;
+                let buf = args[1].read_ptr(&self.memory)?.to_ptr()?;
                 let n = self.value_to_primval(args[2], usize)?.to_u64()?;
                 trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
                 let result = if fd == 1 || fd == 2 { // stdout/stderr
@@ -718,7 +714,7 @@ fn call_c_abi(
             "mmap" => {
                 // This is a horrible hack, but well... the guard page mechanism calls mmap and expects a particular return value, so we give it that value
                 let addr = args[0].read_ptr(&self.memory)?;
-                self.write_primval(dest, PrimVal::Ptr(addr), dest_ty)?;
+                self.write_primval(dest, addr, dest_ty)?;
             }
 
             // Hook pthread calls that go to the thread-local storage memory subsystem
@@ -726,8 +722,12 @@ fn call_c_abi(
                 let key_ptr = args[0].read_ptr(&self.memory)?;
 
                 // Extract the function type out of the signature (that seems easier than constructing it ourselves...)
-                let dtor_ptr = args[1].read_ptr(&self.memory)?;
-                let dtor = if dtor_ptr.is_null_ptr() { None } else { Some(self.memory.get_fn(dtor_ptr.alloc_id)?) };
+                let dtor = match args[1].read_ptr(&self.memory)? {
+                    PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr.alloc_id)?),
+                    PrimVal::Bytes(0) => None,
+                    PrimVal::Bytes(_) => return Err(EvalError::ReadBytesAsPointer),
+                    PrimVal::Undef => return Err(EvalError::ReadUndefBytes),
+                };
 
                 // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t.
                 let key_type = self.operand_ty(&arg_operands[0]).builtin_deref(true, ty::LvaluePreference::NoPreference)
@@ -743,7 +743,7 @@ fn call_c_abi(
                     return Err(EvalError::OutOfTls);
                 }
                 // TODO: Does this need checking for alignment?
-                self.memory.write_uint(key_ptr, key, key_size.bytes())?;
+                self.memory.write_uint(key_ptr.to_ptr()?, key, key_size.bytes())?;
 
                 // Return success (0)
                 self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
@@ -759,7 +759,7 @@ fn call_c_abi(
                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
                 let key = self.value_to_primval(args[0], usize)?.to_u64()? as TlsKey;
                 let ptr = self.memory.load_tls(key)?;
-                self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
+                self.write_primval(dest, ptr, dest_ty)?;
             }
             "pthread_setspecific" => {
                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
index 9c4e60a299f4a4cad99e1f73fefe5a45f0538c1f..3862e8c631a6e417f7bcb4251713a3f5f2cf0000 100644 (file)
@@ -2,6 +2,7 @@
 
 use eval_context::EvalContext;
 use memory::Pointer;
+use value::{Value, PrimVal};
 
 use rustc::hir::def_id::DefId;
 use rustc::ty::subst::Substs;
@@ -9,7 +10,7 @@
 use syntax::codemap::DUMMY_SP;
 use syntax::ast;
 
-use error::EvalResult;
+use error::{EvalResult, EvalError};
 
 impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
@@ -73,16 +74,12 @@ pub fn get_vtable(&mut self, ty: Ty<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) ->
     }
 
     pub fn read_drop_type_from_vtable(&self, vtable: Pointer) -> EvalResult<'tcx, Option<ty::Instance<'tcx>>> {
-        let drop_fn = self.memory.read_ptr(vtable)?;
-
-        // just a sanity check
-        assert_eq!(drop_fn.offset, 0);
-
-        // some values don't need to call a drop impl, so the value is null
-        if drop_fn == Pointer::from_int(0) {
-            Ok(None)
-        } else {
-            self.memory.get_fn(drop_fn.alloc_id).map(Some)
+        // we don't care about the pointee type, we just want a pointer
+        match self.read_ptr(vtable, self.tcx.mk_nil_ptr())? {
+            // some values don't need to call a drop impl, so the value is null
+            Value::ByVal(PrimVal::Bytes(0)) => Ok(None),
+            Value::ByVal(PrimVal::Ptr(drop_fn)) => self.memory.get_fn(drop_fn.alloc_id).map(Some),
+            _ => Err(EvalError::ReadBytesAsPointer),
         }
     }
 
index 387002eee7bc2d243b387b25ef923dde9c925c27..ef11c7a8e4752c80415ade9eaefba6833871d1bc 100644 (file)
@@ -2,6 +2,7 @@
 #![allow(float_cmp)]
 
 use std::mem::transmute;
+use rustc::ty::layout::TargetDataLayout;
 
 use error::{EvalError, EvalResult};
 use memory::{Memory, Pointer};
@@ -47,7 +48,7 @@ pub enum Value {
 /// `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.
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
 pub enum PrimVal {
     /// The raw bytes of a simple value.
     Bytes(u128),
@@ -74,33 +75,33 @@ pub enum PrimValKind {
 }
 
 impl<'a, 'tcx: 'a> Value {
-    pub(super) fn read_ptr(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> {
+    pub(super) fn read_ptr(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, PrimVal> {
         use self::Value::*;
         match *self {
             ByRef(ptr) => mem.read_ptr(ptr),
-            ByVal(ptr) | ByValPair(ptr, _) => ptr.to_ptr(),
+            ByVal(ptr) | ByValPair(ptr, _) => Ok(ptr),
         }
     }
 
     pub(super) fn expect_ptr_vtable_pair(
         &self,
         mem: &Memory<'a, 'tcx>
-    ) -> EvalResult<'tcx, (Pointer, Pointer)> {
+    ) -> EvalResult<'tcx, (PrimVal, Pointer)> {
         use self::Value::*;
         match *self {
             ByRef(ref_ptr) => {
                 let ptr = mem.read_ptr(ref_ptr)?;
                 let vtable = mem.read_ptr(ref_ptr.offset(mem.pointer_size(), mem.layout)?)?;
-                Ok((ptr, vtable))
+                Ok((ptr, vtable.to_ptr()?))
             }
 
-            ByValPair(ptr, vtable) => Ok((ptr.to_ptr()?, vtable.to_ptr()?)),
+            ByValPair(ptr, vtable) => Ok((ptr, vtable.to_ptr()?)),
 
             _ => bug!("expected ptr and vtable, got {:?}", self),
         }
     }
 
-    pub(super) fn expect_slice(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, (Pointer, u64)> {
+    pub(super) fn expect_slice(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, (PrimVal, u64)> {
         use self::Value::*;
         match *self {
             ByRef(ref_ptr) => {
@@ -111,7 +112,7 @@ pub(super) fn expect_slice(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, (P
             ByValPair(ptr, val) => {
                 let len = val.to_u128()?;
                 assert_eq!(len as u64 as u128, len);
-                Ok((ptr.to_ptr()?, len as u64))
+                Ok((ptr, len as u64))
             },
             _ => unimplemented!(),
         }
@@ -146,14 +147,14 @@ pub fn from_char(c: char) -> Self {
     pub fn to_bytes(self) -> EvalResult<'tcx, u128> {
         match self {
             PrimVal::Bytes(b) => Ok(b),
-            PrimVal::Ptr(p) => p.to_int().map(|b| b as u128),
+            PrimVal::Ptr(_) => Err(EvalError::ReadPointerAsBytes),
             PrimVal::Undef => Err(EvalError::ReadUndefBytes),
         }
     }
 
     pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
         match self {
-            PrimVal::Bytes(b) => Ok(Pointer::from_int(b as u64)),
+            PrimVal::Bytes(_) => Err(EvalError::ReadBytesAsPointer),
             PrimVal::Ptr(p) => Ok(p),
             PrimVal::Undef => Err(EvalError::ReadUndefBytes),
         }
@@ -203,6 +204,67 @@ pub fn to_bool(self) -> EvalResult<'tcx, bool> {
             _ => Err(EvalError::InvalidBool),
         }
     }
+
+    pub fn signed_offset(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
+        match self {
+            PrimVal::Bytes(b) => {
+                assert_eq!(b as u64 as u128, b);
+                Ok(PrimVal::Bytes(signed_offset(b as u64, i, layout)? as u128))
+            },
+            PrimVal::Ptr(ptr) => ptr.signed_offset(i, layout).map(PrimVal::Ptr),
+            PrimVal::Undef => Err(EvalError::ReadUndefBytes),
+        }
+    }
+
+    pub fn offset(self, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
+        match self {
+            PrimVal::Bytes(b) => {
+                assert_eq!(b as u64 as u128, b);
+                Ok(PrimVal::Bytes(offset(b as u64, i, layout)? as u128))
+            },
+            PrimVal::Ptr(ptr) => ptr.offset(i, layout).map(PrimVal::Ptr),
+            PrimVal::Undef => Err(EvalError::ReadUndefBytes),
+        }
+    }
+
+    pub fn wrapping_signed_offset(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
+        match self {
+            PrimVal::Bytes(b) => {
+                assert_eq!(b as u64 as u128, b);
+                Ok(PrimVal::Bytes(wrapping_signed_offset(b as u64, i, layout) as u128))
+            },
+            PrimVal::Ptr(ptr) => Ok(PrimVal::Ptr(ptr.wrapping_signed_offset(i, layout))),
+            PrimVal::Undef => Err(EvalError::ReadUndefBytes),
+        }
+    }
+}
+
+pub fn signed_offset<'tcx>(val: u64, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, u64> {
+    // FIXME: is it possible to over/underflow here?
+    if i < 0 {
+        // trickery to ensure that i64::min_value() works fine
+        // this formula only works for true negative values, it panics for zero!
+        let n = u64::max_value() - (i as u64) + 1;
+        val.checked_sub(n).ok_or(EvalError::OverflowingMath)
+    } else {
+        offset(val, i as u64, layout)
+    }
+}
+
+pub fn offset<'tcx>(val: u64, i: u64, layout: &TargetDataLayout) -> EvalResult<'tcx, u64> {
+    if let Some(res) = val.checked_add(i) {
+        if res as u128 >= (1u128 << layout.pointer_size.bits()) {
+            Err(EvalError::OverflowingMath)
+        } else {
+            Ok(res)
+        }
+    } else {
+        Err(EvalError::OverflowingMath)
+    }
+}
+
+pub fn wrapping_signed_offset<'tcx>(val: u64, i: i64, layout: &TargetDataLayout) -> u64 {
+    (val.wrapping_add(i as u64) as u128 % (1u128 << layout.pointer_size.bits())) as u64
 }
 
 impl PrimValKind {
index 030bed6a35298430e449ed7f5b79a4c7cbe4d68d..96469814be29b04c198e5b46548131bdc6ad4049 100644 (file)
@@ -4,5 +4,5 @@ fn main() {
         std::mem::transmute::<&usize, &fn(i32)>(&b)
     };
 
-    (*g)(42) //~ ERROR tried to use an integer pointer or a dangling pointer as a function pointer
+    (*g)(42) //~ ERROR a memory access tried to interpret some bytes as a pointer
 }
index dc39f7dda1b638dac4136c1ba8fa2e82ff4f53ca..28d56a2cb6271815f85b332888a2b870eed930d0 100644 (file)
@@ -3,5 +3,5 @@ fn main() {
         std::mem::transmute::<usize, fn(i32)>(42)
     };
 
-    g(42) //~ ERROR tried to use an integer pointer or a dangling pointer as a function pointer
+    g(42) //~ ERROR a memory access tried to interpret some bytes as a pointer
 }
index fcf34ed44c93aa523d2fd73dbb939a8a3e056bb6..20b93aab1607dd90d19f1c8f2101f3f114e84e00 100644 (file)
@@ -1,4 +1,4 @@
 fn main() {
-    let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: tried to access memory through an invalid pointer
+    let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: a memory access tried to interpret some bytes as a pointer
     panic!("this should never print: {}", x);
 }
index 937546fdc350ac17d315c8af1a40b7a322ffa47e..373e308e1c02d0f817caa99bbb7ab49f25e160c2 100644 (file)
@@ -1,5 +1,5 @@
 fn main() {
     let p = 42 as *const i32;
-    let x = unsafe { *p }; //~ ERROR: tried to access memory through an invalid pointer
+    let x = unsafe { *p }; //~ ERROR: a memory access tried to interpret some bytes as a pointer
     panic!("this should never print: {}", x);
 }