]> git.lizzy.rs Git - rust.git/blobdiff - src/helpers.rs
Detect `std` by checking if the crate defines `#[lang = "start"]` rather than string...
[rust.git] / src / helpers.rs
index 8a7657745b645a796f1e07a76f57c70fd594c263..7f99aa1997068ae3099f0d01112423af4b71e488 100644 (file)
@@ -5,10 +5,10 @@
 
 use log::trace;
 
-use rustc_middle::mir;
-use rustc_middle::ty::{self, List, TyCtxt, layout::TyAndLayout};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
-use rustc_target::abi::{LayoutOf, Size, FieldsShape, Variants};
+use rustc_middle::mir;
+use rustc_middle::ty::{self, layout::TyAndLayout, List, TyCtxt};
+use rustc_target::abi::{Align, FieldsShape, LayoutOf, Size, Variants};
 use rustc_target::spec::abi::Abi;
 
 use rand::RngCore;
@@ -19,10 +19,8 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
 
 /// Gets an instance for a path.
 fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option<DefId> {
-    tcx.crates()
-        .iter()
-        .find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0])
-        .and_then(|krate| {
+    tcx.crates().iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then(
+        |krate| {
             let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX };
             let mut items = tcx.item_children(krate);
             let mut path_it = path.iter().skip(1).peekable();
@@ -40,7 +38,8 @@ fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option<DefId
                 }
             }
             None
-        })
+        },
+    )
 }
 
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
@@ -53,10 +52,7 @@ fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> {
 
     /// Evaluates the scalar at the specified path. Returns Some(val)
     /// if the path could be resolved, and None otherwise
-    fn eval_path_scalar(
-        &mut self,
-        path: &[&str],
-    ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+    fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
         let this = self.eval_context_mut();
         let instance = this.resolve_path(path);
         let cid = GlobalId { instance, promoted: None };
@@ -67,9 +63,7 @@ fn eval_path_scalar(
 
     /// Helper function to get a `libc` constant as a `Scalar`.
     fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
-        self.eval_context_mut()
-            .eval_path_scalar(&["libc", name])?
-            .check_init()
+        self.eval_context_mut().eval_path_scalar(&["libc", name])?.check_init()
     }
 
     /// Helper function to get a `libc` constant as an `i32`.
@@ -101,7 +95,9 @@ fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>
     /// 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]).ty(*this.tcx, ty::ParamEnv::reveal_all());
+        let ty = this
+            .resolve_path(&["std", "sys", "windows", "c", name])
+            .ty(*this.tcx, ty::ParamEnv::reveal_all());
         this.layout_of(ty)
     }
 
@@ -169,8 +165,12 @@ fn call_function(
         let this = self.eval_context_mut();
         let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private.
         let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi();
-        if callee_abi != caller_abi {
-            throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name())
+        if this.machine.enforce_abi && callee_abi != caller_abi {
+            throw_ub_format!(
+                "calling a function with ABI {} using caller ABI {}",
+                callee_abi.name(),
+                caller_abi.name()
+            )
         }
 
         // Push frame.
@@ -181,9 +181,9 @@ fn call_function(
         let mut callee_args = this.frame().body.args_iter();
         for arg in args {
             let callee_arg = this.local_place(
-                callee_args.next().ok_or_else(||
-                    err_ub_format!("callee has fewer arguments than expected")
-                )?
+                callee_args
+                    .next()
+                    .ok_or_else(|| err_ub_format!("callee has fewer arguments than expected"))?,
             )?;
             this.write_immediate(*arg, &callee_arg)?;
         }
@@ -356,7 +356,11 @@ fn visit_aggregate(
                 }
             }
 
-            fn visit_union(&mut self, _v: &MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> {
+            fn visit_union(
+                &mut self,
+                _v: &MPlaceTy<'tcx, Tag>,
+                _fields: NonZeroUsize,
+            ) -> InterpResult<'tcx> {
                 bug!("we should have already handled unions in `visit_value`")
             }
         }
@@ -465,12 +469,21 @@ fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'t
             })?
         } else if target.families.contains(&"windows".to_owned()) {
             // FIXME: we have to finish implementing the Windows equivalent of this.
-            this.eval_windows("c", match e.kind() {
-                NotFound => "ERROR_FILE_NOT_FOUND",
-                _ => throw_unsup_format!("io error {} cannot be transformed into a raw os error", e)
-            })?
+            this.eval_windows(
+                "c",
+                match e.kind() {
+                    NotFound => "ERROR_FILE_NOT_FOUND",
+                    _ => throw_unsup_format!(
+                        "io error {} cannot be transformed into a raw os error",
+                        e
+                    ),
+                },
+            )?
         } else {
-            throw_unsup_format!("setting the last OS error from an io::Error is unsupported for {}.", target_os)
+            throw_unsup_format!(
+                "setting the last OS error from an io::Error is unsupported for {}.",
+                target_os
+            )
         };
         this.set_last_error(last_error)
     }
@@ -553,26 +566,89 @@ fn read_timespec(
             Duration::new(seconds, nanoseconds)
         })
     }
+
+    fn read_c_str<'a>(&'a self, sptr: Scalar<Tag>) -> InterpResult<'tcx, &'a [u8]>
+    where
+        'tcx: 'a,
+        'mir: 'a,
+    {
+        let this = self.eval_context_ref();
+        let size1 = Size::from_bytes(1);
+        let ptr = this.force_ptr(sptr)?; // We need to read at least 1 byte, so we can eagerly get a ptr.
+
+        // Step 1: determine the length.
+        let mut len = Size::ZERO;
+        loop {
+            // FIXME: We are re-getting the allocation each time around the loop.
+            // Would be nice if we could somehow "extend" an existing AllocRange.
+            let alloc = this.memory.get(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result
+            let byte = alloc.read_scalar(alloc_range(Size::ZERO, size1))?.to_u8()?;
+            if byte == 0 {
+                break;
+            } else {
+                len = len + size1;
+            }
+        }
+
+        // Step 2: get the bytes.
+        this.memory.read_bytes(ptr.into(), len)
+    }
+
+    fn read_wide_str(&self, sptr: Scalar<Tag>) -> InterpResult<'tcx, Vec<u16>> {
+        let this = self.eval_context_ref();
+        let size2 = Size::from_bytes(2);
+        let align2 = Align::from_bytes(2).unwrap();
+
+        let mut ptr = this.force_ptr(sptr)?; // We need to read at least 1 wchar, so we can eagerly get a ptr.
+        let mut wchars = Vec::new();
+        loop {
+            // FIXME: We are re-getting the allocation each time around the loop.
+            // Would be nice if we could somehow "extend" an existing AllocRange.
+            let alloc = this.memory.get(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result
+            let wchar = alloc.read_scalar(alloc_range(Size::ZERO, size2))?.to_u16()?;
+            if wchar == 0 {
+                break;
+            } else {
+                wchars.push(wchar);
+                ptr = ptr.offset(size2, this)?;
+            }
+        }
+
+        Ok(wchars)
+    }
+
+    /// Check that the ABI is what we expect.
+    fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
+        if self.eval_context_ref().machine.enforce_abi && abi != exp_abi {
+            throw_ub_format!(
+                "calling a function with ABI {} using caller ABI {}",
+                exp_abi.name(),
+                abi.name()
+            )
+        }
+        Ok(())
+    }
+
+    fn in_std(&self) -> bool {
+        let this = self.eval_context_ref();
+        this.tcx.def_path(this.frame().instance.def_id()).krate
+            == this.tcx.def_path(this.tcx.lang_items().start_fn().unwrap()).krate
+    }
 }
 
 /// 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>]> {
+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)
 }
 
-/// Check that the ABI is what we expect.
-pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
-    if abi == exp_abi {
-        Ok(())
-    } else {
-        throw_ub_format!("calling a function with ABI {} using caller ABI {}", exp_abi.name(), abi.name())
-    }
-}
-
 pub fn isolation_error(name: &str) -> InterpResult<'static> {
     throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
         "{} not available when isolation is enabled",