]> git.lizzy.rs Git - rust.git/blobdiff - src/helpers.rs
fix diagnostics printing when triggered during TLS dtor scheduling
[rust.git] / src / helpers.rs
index 9f46a0c1ce2d9e3d8a49c5db4639590e23f36985..d271b845c21511c14ca85ebffdb2d8dd676c0e32 100644 (file)
@@ -1,5 +1,6 @@
-use std::convert::TryFrom;
+use std::convert::{TryFrom, TryInto};
 use std::mem;
+use std::num::NonZeroUsize;
 
 use log::trace;
 
@@ -12,7 +13,7 @@
 
 use crate::*;
 
-impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
 
 /// Gets an instance for a path.
 fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option<DefId> {
@@ -53,7 +54,7 @@ fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> {
     fn eval_path_scalar(
         &mut self,
         path: &[&str],
-    ) -> InterpResult<'tcx, ScalarMaybeUndef<Tag>> {
+    ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
         let this = self.eval_context_mut();
         let instance = this.resolve_path(path);
         let cid = GlobalId { instance, promoted: None };
@@ -66,7 +67,7 @@ fn eval_path_scalar(
     fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
         self.eval_context_mut()
             .eval_path_scalar(&["libc", name])?
-            .not_undef()
+            .check_init()
     }
 
     /// Helper function to get a `libc` constant as an `i32`.
@@ -79,7 +80,7 @@ fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> {
     fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
         self.eval_context_mut()
             .eval_path_scalar(&["std", "sys", "windows", module, name])?
-            .not_undef()
+            .check_init()
     }
 
     /// Helper function to get a `windows` constant as an `u64`.
@@ -91,14 +92,14 @@ fn eval_windows_u64(&mut self, module: &str, name: &str) -> InterpResult<'tcx, u
     /// Helper function to get the `TyAndLayout` of a `libc` type
     fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
         let this = self.eval_context_mut();
-        let ty = this.resolve_path(&["libc", name]).monomorphic_ty(*this.tcx);
+        let ty = this.resolve_path(&["libc", name]).ty(*this.tcx, ty::ParamEnv::reveal_all());
         this.layout_of(ty)
     }
 
     /// Helper function to get the `TyAndLayout` of a `windows` type
     fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
         let this = self.eval_context_mut();
-        let ty = this.resolve_path(&["std", "sys", "windows", "c", name]).monomorphic_ty(*this.tcx);
+        let ty = this.resolve_path(&["std", "sys", "windows", "c", name]).ty(*this.tcx, ty::ParamEnv::reveal_all());
         this.layout_of(ty)
     }
 
@@ -264,7 +265,7 @@ struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
             unsafe_cell_action: F,
         }
 
-        impl<'ecx, 'mir, 'tcx, F> ValueVisitor<'mir, 'tcx, Evaluator<'tcx>>
+        impl<'ecx, 'mir, 'tcx: 'mir, F> ValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>>
             for UnsafeCellVisitor<'ecx, 'mir, 'tcx, F>
         where
             F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>,
@@ -290,6 +291,9 @@ fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
                 } else if self.ecx.type_is_freeze(v.layout.ty) {
                     // This is `Freeze`, there cannot be an `UnsafeCell`
                     Ok(())
+                } else if matches!(v.layout.fields, FieldsShape::Union(..)) {
+                    // A (non-frozen) union. We fall back to whatever the type says.
+                    (self.unsafe_cell_action)(v)
                 } else {
                     // We want to not actually read from memory for this visit. So, before
                     // walking this value, we have to make sure it is not a
@@ -333,22 +337,15 @@ fn visit_aggregate(
                         places.sort_by_key(|place| place.ptr.assert_ptr().offset);
                         self.walk_aggregate(place, places.into_iter().map(Ok))
                     }
-                    FieldsShape::Union { .. } => {
+                    FieldsShape::Union { .. } | FieldsShape::Primitive => {
                         // Uh, what?
-                        bug!("a union is not an aggregate we should ever visit")
+                        bug!("unions/primitives are not aggregates we should ever visit")
                     }
                 }
             }
 
-            // We have to do *something* for unions.
-            fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>, fields: usize) -> InterpResult<'tcx> {
-                assert!(fields > 0); // we should never reach "pseudo-unions" with 0 fields, like primitives
-
-                // With unions, we fall back to whatever the type says, to hopefully be consistent
-                // with LLVM IR.
-                // FIXME: are we consistent, and is this really the behavior we want?
-                let frozen = self.ecx.type_is_freeze(v.layout.ty);
-                if frozen { Ok(()) } else { (self.unsafe_cell_action)(v) }
+            fn visit_union(&mut self, _v: MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> {
+                bug!("we should have already handled unions in `visit_value`")
             }
         }
     }
@@ -410,7 +407,7 @@ fn set_last_error(&mut self, scalar: Scalar<Tag>) -> InterpResult<'tcx> {
     fn get_last_error(&self) -> InterpResult<'tcx, Scalar<Tag>> {
         let this = self.eval_context_ref();
         let errno_place = this.machine.last_error.unwrap();
-        this.read_scalar(errno_place.into())?.not_undef()
+        this.read_scalar(errno_place.into())?.check_init()
     }
 
     /// Sets the last OS error using a `std::io::Error`. This function tries to produce the most
@@ -470,6 +467,46 @@ fn try_unwrap_io_result<T: From<i32>>(
             }
         }
     }
+
+    fn read_scalar_at_offset(
+        &self,
+        op: OpTy<'tcx, Tag>,
+        offset: u64,
+        layout: TyAndLayout<'tcx>,
+    ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+        let this = self.eval_context_ref();
+        let op_place = this.deref_operand(op)?;
+        let offset = Size::from_bytes(offset);
+        // Ensure that the following read at an offset is within bounds
+        assert!(op_place.layout.size >= offset + layout.size);
+        let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?;
+        this.read_scalar(value_place.into())
+    }
+
+    fn write_scalar_at_offset(
+        &mut self,
+        op: OpTy<'tcx, Tag>,
+        offset: u64,
+        value: impl Into<ScalarMaybeUninit<Tag>>,
+        layout: TyAndLayout<'tcx>,
+    ) -> InterpResult<'tcx, ()> {
+        let this = self.eval_context_mut();
+        let op_place = this.deref_operand(op)?;
+        let offset = Size::from_bytes(offset);
+        // Ensure that the following read at an offset is within bounds
+        assert!(op_place.layout.size >= offset + layout.size);
+        let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?;
+        this.write_scalar(value, value_place.into())
+    }
+}
+
+/// Check that the number of args is what we expect.
+pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]>
+    where &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]> {
+    if let Ok(ops) = args.try_into() {
+        return Ok(ops);
+    }
+    throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N)
 }
 
 pub fn immty_from_int_checked<'tcx>(