]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #1131 - JOE1994:alloc_os_str_as_c_str, r=RalfJung
authorbors <bors@rust-lang.org>
Mon, 30 Dec 2019 19:15:53 +0000 (19:15 +0000)
committerbors <bors@rust-lang.org>
Mon, 30 Dec 2019 19:15:53 +0000 (19:15 +0000)
Add helper 'alloc_os_str_as_c_str' and use it in env_var emulation

First part of the plan laid out in #707 (comment).

Re-submitting a pull-request for work from  #1098 (manual rebasing..)

r? @RalfJung

src/helpers.rs
src/shims/env.rs
src/shims/foreign_items.rs

index 242e2b1d4a13d18acb70825cf1571e6897e18cc3..18b433a0e4a50a7a1a92c7a58ed368893979700a 100644 (file)
@@ -497,6 +497,20 @@ fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]>
             .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?;
         Ok(true)
     }
+
+    fn alloc_os_str_as_c_str(
+        &mut self,
+        os_str: &OsStr,
+        memkind: MemoryKind<MiriMemoryKind>
+    ) -> Pointer<Tag> {
+        let size = os_str.len() as u64 + 1; // Make space for `0` terminator.
+        let this = self.eval_context_mut();
+
+        let arg_type = this.tcx.mk_array(this.tcx.types.u8, size);
+        let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind);
+        self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap();
+        arg_place.ptr.assert_ptr()
+    }
 }
 
 pub fn immty_from_int_checked<'tcx>(
index 1e655ca821d811d6394305cbc62df830fdbfa81c..1151561553f922f264174a071aa8ddaf673ee5c2 100644 (file)
@@ -1,18 +1,18 @@
 use std::collections::HashMap;
-use std::ffi::OsString;
+use std::ffi::{OsString, OsStr};
 use std::env;
 
 use crate::stacked_borrows::Tag;
 use crate::*;
 
 use rustc::ty::layout::Size;
-use rustc_mir::interpret::{Memory, Pointer};
+use rustc_mir::interpret::Pointer;
 
 #[derive(Default)]
 pub struct EnvVars {
     /// Stores pointers to the environment variables. These variables must be stored as
     /// null-terminated C strings with the `"{name}={value}"` format.
-    map: HashMap<Vec<u8>, Pointer<Tag>>,
+    map: HashMap<OsString, Pointer<Tag>>,
 }
 
 impl EnvVars {
@@ -30,24 +30,23 @@ pub(crate) fn init<'mir, 'tcx>(
             for (name, value) in env::vars() {
                 if !excluded_env_vars.contains(&name) {
                     let var_ptr =
-                        alloc_env_var(name.as_bytes(), value.as_bytes(), &mut ecx.memory);
-                    ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr);
+                        alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx);
+                    ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr);
                 }
             }
         }
     }
 }
 
-fn alloc_env_var<'mir, 'tcx>(
-    name: &[u8],
-    value: &[u8],
-    memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>,
+fn alloc_env_var_as_c_str<'mir, 'tcx>(
+    name: &OsStr,
+    value: &OsStr,
+    ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
 ) -> Pointer<Tag> {
-    let mut bytes = name.to_vec();
-    bytes.push(b'=');
-    bytes.extend_from_slice(value);
-    bytes.push(0);
-    memory.allocate_static_bytes(bytes.as_slice(), MiriMemoryKind::Env.into())
+    let mut name_osstring = name.to_os_string();
+    name_osstring.push("=");
+    name_osstring.push(value);
+    ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into())
 }
 
 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
@@ -56,7 +55,7 @@ fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar<Tag>
         let this = self.eval_context_mut();
 
         let name_ptr = this.read_scalar(name_op)?.not_undef()?;
-        let name = this.memory.read_c_str(name_ptr)?;
+        let name = this.read_os_str_from_c_str(name_ptr)?;
         Ok(match this.machine.env_vars.map.get(name) {
             // The offset is used to strip the "{name}=" part of the string.
             Some(var_ptr) => {
@@ -71,20 +70,20 @@ fn setenv(
         name_op: OpTy<'tcx, Tag>,
         value_op: OpTy<'tcx, Tag>,
     ) -> InterpResult<'tcx, i32> {
-        let this = self.eval_context_mut();
+        let mut this = self.eval_context_mut();
 
         let name_ptr = this.read_scalar(name_op)?.not_undef()?;
         let value_ptr = this.read_scalar(value_op)?.not_undef()?;
-        let value = this.memory.read_c_str(value_ptr)?;
+        let value = this.read_os_str_from_c_str(value_ptr)?;
         let mut new = None;
         if !this.is_null(name_ptr)? {
-            let name = this.memory.read_c_str(name_ptr)?;
-            if !name.is_empty() && !name.contains(&b'=') {
+            let name = this.read_os_str_from_c_str(name_ptr)?;
+            if !name.is_empty() && !name.to_string_lossy().contains('=') {
                 new = Some((name.to_owned(), value.to_owned()));
             }
         }
         if let Some((name, value)) = new {
-            let var_ptr = alloc_env_var(&name, &value, &mut this.memory);
+            let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this);
             if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) {
                 this.memory
                     .deallocate(var, None, MiriMemoryKind::Env.into())?;
@@ -101,8 +100,8 @@ fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
         let name_ptr = this.read_scalar(name_op)?.not_undef()?;
         let mut success = None;
         if !this.is_null(name_ptr)? {
-            let name = this.memory.read_c_str(name_ptr)?.to_owned();
-            if !name.is_empty() && !name.contains(&b'=') {
+            let name = this.read_os_str_from_c_str(name_ptr)?.to_owned();
+            if !name.is_empty() && !name.to_string_lossy().contains('=') {
                 success = Some(this.machine.env_vars.map.remove(&name));
             }
         }
index 5bdd12b4eb1d264eccad6416062344987608c9aa..07e3b7d7582650d37f0cb66b0a069bcb483034e4 100644 (file)
@@ -956,10 +956,22 @@ fn emulate_foreign_item(
                 this.write_null(dest)?;
             }
             "GetEnvironmentVariableW" => {
+                // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars)
+                // args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars)
+                // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string.
+                // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator.
+                // Return 0 upon failure.
+                
                 // This is not the env var you are looking for.
                 this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND
                 this.write_null(dest)?;
             }
+            "SetEnvironmentVariableW" => {
+                // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars)
+                // args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars)
+                // Return nonzero if success, else return 0.
+                throw_unsup_format!("can't set environment variable on Windows");
+            }
             "GetCommandLineW" => {
                 this.write_scalar(
                     this.machine.cmd_line.expect("machine must be initialized"),