]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/interpret/validity.rs
factor wide ptr metadata checking into separate method
[rust.git] / src / librustc_mir / interpret / validity.rs
index ea8b88e51f0a0c00b4e99cd0c9a958579c1b60cd..f358a21f4af76c812f55ee8a30d5a27aea936d77 100644 (file)
 use std::hash::Hash;
 
 use super::{
-    GlobalAlloc, InterpResult, InterpError,
-    OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy, UnsupportedInfo::*,
+    GlobalAlloc, InterpResult,
+    Scalar, OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy,
 };
 
-macro_rules! validation_failure {
+macro_rules! throw_validation_failure {
     ($what:expr, $where:expr, $details:expr) => {{
         let where_ = path_format(&$where);
         let where_ = if where_.is_empty() {
@@ -22,7 +22,7 @@ macro_rules! validation_failure {
         } else {
             format!(" at {}", where_)
         };
-        err!(ValidationFailure(format!(
+        throw_unsup!(ValidationFailure(format!(
             "encountered {}{}, but expected {}",
             $what, where_, $details,
         )))
@@ -34,7 +34,7 @@ macro_rules! validation_failure {
         } else {
             format!(" at {}", where_)
         };
-        err!(ValidationFailure(format!(
+        throw_unsup!(ValidationFailure(format!(
             "encountered {}{}",
             $what, where_,
         )))
@@ -45,14 +45,14 @@ macro_rules! try_validation {
     ($e:expr, $what:expr, $where:expr, $details:expr) => {{
         match $e {
             Ok(x) => x,
-            Err(_) => return validation_failure!($what, $where, $details),
+            Err(_) => throw_validation_failure!($what, $where, $details),
         }
     }};
 
     ($e:expr, $what:expr, $where:expr) => {{
         match $e {
             Ok(x) => x,
-            Err(_) => return validation_failure!($what, $where),
+            Err(_) => throw_validation_failure!($what, $where),
         }
     }}
 }
@@ -250,6 +250,44 @@ fn visit_elem(
         self.path.truncate(path_len);
         Ok(())
     }
+
+    fn check_wide_ptr_meta(
+        &mut self,
+        meta: Option<Scalar<M::PointerTag>>,
+        pointee: TyLayout<'tcx>,
+    ) -> InterpResult<'tcx> {
+        let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
+        match tail.sty {
+            ty::Dynamic(..) => {
+                let vtable = meta.unwrap();
+                try_validation!(
+                    self.ecx.memory.check_ptr_access(
+                        vtable,
+                        3*self.ecx.tcx.data_layout.pointer_size, // drop, size, align
+                        self.ecx.tcx.data_layout.pointer_align.abi,
+                    ),
+                    "dangling or unaligned vtable pointer in wide pointer or too small vtable",
+                    self.path
+                );
+                try_validation!(self.ecx.read_drop_type_from_vtable(vtable),
+                    "invalid drop fn in vtable", self.path);
+                try_validation!(self.ecx.read_size_and_align_from_vtable(vtable),
+                    "invalid size or align in vtable", self.path);
+                // FIXME: More checks for the vtable.
+            }
+            ty::Slice(..) | ty::Str => {
+                try_validation!(meta.unwrap().to_usize(self.ecx),
+                    "non-integer slice length in wide pointer", self.path);
+            }
+            ty::Foreign(..) => {
+                // Unsized, but not wide.
+            }
+            _ =>
+                bug!("Unexpected unsized type tail: {:?}", tail),
+        }
+
+        Ok(())
+    }
 }
 
 impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
@@ -297,12 +335,12 @@ fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx>
         match self.walk_value(op) {
             Ok(()) => Ok(()),
             Err(err) => match err.kind {
-                InterpError::Unsupported(InvalidDiscriminant(val)) =>
-                    validation_failure!(
+                err_unsup!(InvalidDiscriminant(val)) =>
+                    throw_validation_failure!(
                         val, self.path, "a valid enum discriminant"
                     ),
-                InterpError::Unsupported(ReadPointerAsBytes) =>
-                    validation_failure!(
+                err_unsup!(ReadPointerAsBytes) =>
+                    throw_validation_failure!(
                         "a pointer", self.path, "plain (non-pointer) bytes"
                     ),
                 _ => Err(err),
@@ -353,44 +391,15 @@ fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<
                 }
             }
             _ if ty.is_box() || ty.is_region_ptr() => {
-                // Handle fat pointers.
+                // Handle wide pointers.
                 // Check metadata early, for better diagnostics
                 let ptr = try_validation!(value.to_scalar_ptr(),
                     "undefined address in pointer", self.path);
                 let meta = try_validation!(value.to_meta(),
-                    "uninitialized data in fat pointer metadata", self.path);
+                    "uninitialized data in wide pointer metadata", self.path);
                 let layout = self.ecx.layout_of(value.layout.ty.builtin_deref(true).unwrap().ty)?;
                 if layout.is_unsized() {
-                    let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(layout.ty,
-                                                                          self.ecx.param_env);
-                    match tail.sty {
-                        ty::Dynamic(..) => {
-                            let vtable = meta.unwrap();
-                            try_validation!(
-                                self.ecx.memory.check_ptr_access(
-                                    vtable,
-                                    3*self.ecx.tcx.data_layout.pointer_size, // drop, size, align
-                                    self.ecx.tcx.data_layout.pointer_align.abi,
-                                ),
-                                "dangling or unaligned vtable pointer or too small vtable",
-                                self.path
-                            );
-                            try_validation!(self.ecx.read_drop_type_from_vtable(vtable),
-                                "invalid drop fn in vtable", self.path);
-                            try_validation!(self.ecx.read_size_and_align_from_vtable(vtable),
-                                "invalid size or align in vtable", self.path);
-                            // FIXME: More checks for the vtable.
-                        }
-                        ty::Slice(..) | ty::Str => {
-                            try_validation!(meta.unwrap().to_usize(self.ecx),
-                                "non-integer slice length in fat pointer", self.path);
-                        }
-                        ty::Foreign(..) => {
-                            // Unsized, but not fat.
-                        }
-                        _ =>
-                            bug!("Unexpected unsized type tail: {:?}", tail),
-                    }
+                    self.check_wide_ptr_meta(meta, layout)?;
                 }
                 // Make sure this is dereferencable and all.
                 let (size, align) = self.ecx.size_and_align_of(meta, layout)?
@@ -398,7 +407,9 @@ fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<
                     // alignment and size determined by the layout (size will be 0,
                     // alignment should take attributes into account).
                     .unwrap_or_else(|| (layout.size, layout.align.abi));
-                let ptr: Option<_> = match self.ecx.memory.check_ptr_access(ptr, size, align) {
+                let ptr: Option<_> = match
+                    self.ecx.memory.check_ptr_access_align(ptr, size, Some(align))
+                {
                     Ok(ptr) => ptr,
                     Err(err) => {
                         info!(
@@ -406,19 +417,19 @@ fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<
                             ptr, size, align
                         );
                         match err.kind {
-                            InterpError::Unsupported(InvalidNullPointerUsage) =>
-                                return validation_failure!("NULL reference", self.path),
-                            InterpError::Unsupported(AlignmentCheckFailed { required, has }) =>
-                                return validation_failure!(format!("unaligned reference \
+                            err_unsup!(InvalidNullPointerUsage) =>
+                                throw_validation_failure!("NULL reference", self.path),
+                            err_unsup!(AlignmentCheckFailed { required, has }) =>
+                                throw_validation_failure!(format!("unaligned reference \
                                     (required {} byte alignment but found {})",
                                     required.bytes(), has.bytes()), self.path),
-                            InterpError::Unsupported(ReadBytesAsPointer) =>
-                                return validation_failure!(
+                            err_unsup!(ReadBytesAsPointer) =>
+                                throw_validation_failure!(
                                     "dangling reference (created from integer)",
                                     self.path
                                 ),
                             _ =>
-                                return validation_failure!(
+                                throw_validation_failure!(
                                     "dangling reference (not entirely in bounds)",
                                     self.path
                                 ),
@@ -478,7 +489,7 @@ fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<
 
     fn visit_uninhabited(&mut self) -> InterpResult<'tcx>
     {
-        validation_failure!("a value of an uninhabited type", self.path)
+        throw_validation_failure!("a value of an uninhabited type", self.path)
     }
 
     fn visit_scalar(
@@ -511,27 +522,27 @@ fn visit_scalar(
                 if lo == 1 && hi == max_hi {
                     // Only NULL is the niche.  So make sure the ptr is NOT NULL.
                     if self.ecx.memory.ptr_may_be_null(ptr) {
-                        return validation_failure!(
+                        throw_validation_failure!(
                             "a potentially NULL pointer",
                             self.path,
                             format!(
                                 "something that cannot possibly fail to be {}",
                                 wrapping_range_format(&layout.valid_range, max_hi)
                             )
-                        );
+                        )
                     }
                     return Ok(());
                 } else {
                     // Conservatively, we reject, because the pointer *could* have a bad
                     // value.
-                    return validation_failure!(
+                    throw_validation_failure!(
                         "a pointer",
                         self.path,
                         format!(
                             "something that cannot possibly fail to be {}",
                             wrapping_range_format(&layout.valid_range, max_hi)
                         )
-                    );
+                    )
                 }
             }
             Ok(data) =>
@@ -541,7 +552,7 @@ fn visit_scalar(
         if wrapping_range_contains(&layout.valid_range, bits) {
             Ok(())
         } else {
-            validation_failure!(
+            throw_validation_failure!(
                 bits,
                 self.path,
                 format!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
@@ -608,16 +619,14 @@ fn visit_aggregate(
                     Err(err) => {
                         // For some errors we might be able to provide extra information
                         match err.kind {
-                            InterpError::Unsupported(ReadUndefBytes(offset)) => {
+                            err_unsup!(ReadUndefBytes(offset)) => {
                                 // Some byte was undefined, determine which
                                 // element that byte belongs to so we can
                                 // provide an index.
                                 let i = (offset.bytes() / ty_size.bytes()) as usize;
                                 self.path.push(PathElem::ArrayElem(i));
 
-                                return validation_failure!(
-                                    "undefined bytes", self.path
-                                )
+                                throw_validation_failure!("undefined bytes", self.path)
                             },
                             // Other errors shouldn't be possible
                             _ => return Err(err),