about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Schneider <oli-obk@users.noreply.github.com>2017-07-20 07:09:52 +0200
committerGitHub <noreply@github.com>2017-07-20 07:09:52 +0200
commitf02d9e63fde6d692b38b3843b16132c0b79a7ef6 (patch)
treed9ecc6add6a7ded16f8d14c449e4616a9fff3bb1
parent27c64479cd0e449634ef61bbf42dff42cfa1fc28 (diff)
parent7648ccaae1296a43d3050536f9ed774782f9c775 (diff)
downloadrust-f02d9e63fde6d692b38b3843b16132c0b79a7ef6.tar.gz
rust-f02d9e63fde6d692b38b3843b16132c0b79a7ef6.zip
Merge pull request #259 from RalfJung/ref-validate
No longer check aligment and non-NULLness on `&`
-rw-r--r--src/cast.rs4
-rw-r--r--src/eval_context.rs24
-rw-r--r--src/memory.rs8
-rw-r--r--tests/compile-fail/int_ptr_cast.rs5
-rw-r--r--tests/compile-fail/int_ptr_cast2.rs5
-rw-r--r--tests/compile-fail/reference_to_packed.rs4
-rw-r--r--tests/compile-fail/unaligned_ptr_cast.rs2
-rw-r--r--tests/compile-fail/unaligned_ptr_cast2.rs7
8 files changed, 28 insertions, 31 deletions
diff --git a/src/cast.rs b/src/cast.rs
index cb0b1121709..0fa38366e1c 100644
--- a/src/cast.rs
+++ b/src/cast.rs
@@ -46,9 +46,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
     fn cast_int(&self, v: u128, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx, PrimVal> {
         use rustc::ty::TypeVariants::*;
         match ty.sty {
-            TyBool if v == 0 => Ok(PrimVal::from_bool(false)),
-            TyBool if v == 1 => Ok(PrimVal::from_bool(true)),
-            TyBool => Err(EvalError::InvalidBool),
+            // Casts to bool are not permitted by rustc, no need to handle them here.
 
             TyInt(IntTy::I8)  => Ok(PrimVal::Bytes(v as i128 as i8  as u128)),
             TyInt(IntTy::I16) => Ok(PrimVal::Bytes(v as i128 as i16 as u128)),
diff --git a/src/eval_context.rs b/src/eval_context.rs
index 2f28063ff86..5bcd8368933 100644
--- a/src/eval_context.rs
+++ b/src/eval_context.rs
@@ -670,9 +670,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             Ref(_, _, ref lvalue) => {
                 let src = self.eval_lvalue(lvalue)?;
-                // We ignore the alignment of the lvalue here -- this rvalue produces sth. of type &, which must always be aligned.
+                // We ignore the alignment of the lvalue here -- special handling for packed structs ends
+                // at the `&` operator.
                 let (ptr, extra, _aligned) = self.force_allocation(src)?.to_ptr_extra_aligned();
-                let ty = self.lvalue_ty(lvalue);
 
                 let val = match extra {
                     LvalueExtra::None => ptr.to_value(),
@@ -682,10 +682,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                         bug!("attempted to take a reference to an enum downcast lvalue"),
                 };
 
-                // Check alignment and non-NULLness.
-                let (_, align) = self.size_and_align_of_dst(ty, val)?;
-                self.memory.check_align(ptr, align)?;
-
                 self.write_value(val, dest, dest_ty)?;
             }
 
@@ -1105,6 +1101,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         dest: Lvalue<'tcx>,
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx> {
+        //trace!("Writing {:?} to {:?} at type {:?}", src_val, dest, dest_ty);
         // Note that it is really important that the type here is the right one, and matches the type things are read at.
         // In case `src_val` is a `ByValPair`, we don't do any magic here to handle padding properly, which is only
         // correct if we never look at this data with the wrong type.
@@ -1382,7 +1379,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 // if we transmute a ptr to an isize, reading it back into a primval shouldn't panic
                 // Due to read_ptr ignoring the sign, we need to jump around some hoops
                 match self.memory.read_int(ptr.to_ptr()?, size) {
-                    Err(EvalError::ReadPointerAsBytes) if size == self.memory.pointer_size() => self.memory.read_ptr(ptr.to_ptr()?)?.into_inner_primval(),
+                    Err(EvalError::ReadPointerAsBytes) if size == self.memory.pointer_size() =>
+                        // Reading as an int failed because we are seeing ptr bytes *and* we are actually reading at ptr size.
+                        // Let's try again, reading a ptr this time.
+                        self.memory.read_ptr(ptr.to_ptr()?)?.into_inner_primval(),
                     other => PrimVal::from_i128(other?),
                 }
             }
@@ -1397,11 +1397,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                     U128 => 16,
                     Us => self.memory.pointer_size(),
                 };
-                if size == self.memory.pointer_size() {
-                    // if we transmute a ptr to an usize, reading it back into a primval shouldn't panic
-                    self.memory.read_ptr(ptr.to_ptr()?)?.into_inner_primval()
-                } else {
-                    PrimVal::from_u128(self.memory.read_uint(ptr.to_ptr()?, size)?)
+                // if we transmute a ptr to an usize, reading it back into a primval shouldn't panic
+                // for consistency's sake, we use the same code as above
+                match self.memory.read_uint(ptr.to_ptr()?, size) {
+                    Err(EvalError::ReadPointerAsBytes) if size == self.memory.pointer_size() => self.memory.read_ptr(ptr.to_ptr()?)?.into_inner_primval(),
+                    other => PrimVal::from_u128(other?),
                 }
             }
 
diff --git a/src/memory.rs b/src/memory.rs
index cf7f969be8e..71f4c329b5b 100644
--- a/src/memory.rs
+++ b/src/memory.rs
@@ -720,12 +720,14 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
 
     pub fn read_ptr(&self, ptr: MemoryPointer) -> EvalResult<'tcx, Pointer> {
         let size = self.pointer_size();
-        if self.check_defined(ptr, size).is_err() {
-            return Ok(PrimVal::Undef.into());
-        }
         self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer
         let endianess = self.endianess();
         let bytes = self.get_bytes_unchecked(ptr, size, size)?;
+        // Undef check happens *after* we established that the alignment is correct.
+        // We must not return Ok() for unaligned pointers!
+        if self.check_defined(ptr, size).is_err() {
+            return Ok(PrimVal::Undef.into());
+        }
         let offset = read_target_uint(endianess, bytes).unwrap();
         assert_eq!(offset as u64 as u128, offset);
         let offset = offset as u64;
diff --git a/tests/compile-fail/int_ptr_cast.rs b/tests/compile-fail/int_ptr_cast.rs
deleted file mode 100644
index ae5f65a7166..00000000000
--- a/tests/compile-fail/int_ptr_cast.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn main() {
-    let x = 2usize as *const u32;
-    // This must fail because alignment is violated
-    let _ = unsafe { &*x }; //~ ERROR: tried to access memory with alignment 2, but alignment 4 is required
-}
diff --git a/tests/compile-fail/int_ptr_cast2.rs b/tests/compile-fail/int_ptr_cast2.rs
deleted file mode 100644
index 1897066f7bc..00000000000
--- a/tests/compile-fail/int_ptr_cast2.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn main() {
-    let x = 0usize as *const u32;
-    // This must fail because the pointer is NULL
-    let _ = unsafe { &*x }; //~ ERROR: invalid use of NULL pointer
-}
diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs
index 4cf353298b9..5ca733a64df 100644
--- a/tests/compile-fail/reference_to_packed.rs
+++ b/tests/compile-fail/reference_to_packed.rs
@@ -11,6 +11,6 @@ fn main() {
         x: 42,
         y: 99,
     };
-    let p = &foo.x; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required
-    let i = *p;
+    let p = &foo.x;
+    let i = *p; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required
 }
diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast.rs
index fcab430f8fc..8ad1b323250 100644
--- a/tests/compile-fail/unaligned_ptr_cast.rs
+++ b/tests/compile-fail/unaligned_ptr_cast.rs
@@ -2,5 +2,5 @@ fn main() {
     let x = &2u16;
     let x = x as *const _ as *const u32;
     // This must fail because alignment is violated
-    let _ = unsafe { &*x }; //~ ERROR: tried to access memory with alignment 2, but alignment 4 is required
+    let _x = unsafe { *x }; //~ ERROR: tried to access memory with alignment 2, but alignment 4 is required
 }
diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs
new file mode 100644
index 00000000000..15fb7dd3136
--- /dev/null
+++ b/tests/compile-fail/unaligned_ptr_cast2.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let x = &2u16;
+    let x = x as *const _ as *const *const u8;
+    // This must fail because alignment is violated.  Test specifically for loading pointers, which have special code
+    // in miri's memory.
+    let _x = unsafe { *x }; //~ ERROR: tried to access memory with alignment 2, but alignment
+}