Skip to content

Commit 9f79aa9

Browse files
committed
Auto merge of #1131 - JOE1994:alloc_os_str_as_c_str, r=RalfJung
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
2 parents 3fe92f8 + a4bd68a commit 9f79aa9

File tree

3 files changed

+47
-22
lines changed

3 files changed

+47
-22
lines changed

src/helpers.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
497497
.write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?;
498498
Ok(true)
499499
}
500+
501+
fn alloc_os_str_as_c_str(
502+
&mut self,
503+
os_str: &OsStr,
504+
memkind: MemoryKind<MiriMemoryKind>
505+
) -> Pointer<Tag> {
506+
let size = os_str.len() as u64 + 1; // Make space for `0` terminator.
507+
let this = self.eval_context_mut();
508+
509+
let arg_type = this.tcx.mk_array(this.tcx.types.u8, size);
510+
let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind);
511+
self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap();
512+
arg_place.ptr.assert_ptr()
513+
}
500514
}
501515

502516
pub fn immty_from_int_checked<'tcx>(

src/shims/env.rs

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
use std::collections::HashMap;
2-
use std::ffi::OsString;
2+
use std::ffi::{OsString, OsStr};
33
use std::env;
44

55
use crate::stacked_borrows::Tag;
66
use crate::*;
77

88
use rustc::ty::layout::Size;
9-
use rustc_mir::interpret::{Memory, Pointer};
9+
use rustc_mir::interpret::Pointer;
1010

1111
#[derive(Default)]
1212
pub struct EnvVars {
1313
/// Stores pointers to the environment variables. These variables must be stored as
1414
/// null-terminated C strings with the `"{name}={value}"` format.
15-
map: HashMap<Vec<u8>, Pointer<Tag>>,
15+
map: HashMap<OsString, Pointer<Tag>>,
1616
}
1717

1818
impl EnvVars {
@@ -30,24 +30,23 @@ impl EnvVars {
3030
for (name, value) in env::vars() {
3131
if !excluded_env_vars.contains(&name) {
3232
let var_ptr =
33-
alloc_env_var(name.as_bytes(), value.as_bytes(), &mut ecx.memory);
34-
ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr);
33+
alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx);
34+
ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr);
3535
}
3636
}
3737
}
3838
}
3939
}
4040

41-
fn alloc_env_var<'mir, 'tcx>(
42-
name: &[u8],
43-
value: &[u8],
44-
memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>,
41+
fn alloc_env_var_as_c_str<'mir, 'tcx>(
42+
name: &OsStr,
43+
value: &OsStr,
44+
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
4545
) -> Pointer<Tag> {
46-
let mut bytes = name.to_vec();
47-
bytes.push(b'=');
48-
bytes.extend_from_slice(value);
49-
bytes.push(0);
50-
memory.allocate_static_bytes(bytes.as_slice(), MiriMemoryKind::Env.into())
46+
let mut name_osstring = name.to_os_string();
47+
name_osstring.push("=");
48+
name_osstring.push(value);
49+
ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into())
5150
}
5251

5352
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
@@ -56,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
5655
let this = self.eval_context_mut();
5756

5857
let name_ptr = this.read_scalar(name_op)?.not_undef()?;
59-
let name = this.memory.read_c_str(name_ptr)?;
58+
let name = this.read_os_str_from_c_str(name_ptr)?;
6059
Ok(match this.machine.env_vars.map.get(name) {
6160
// The offset is used to strip the "{name}=" part of the string.
6261
Some(var_ptr) => {
@@ -71,20 +70,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
7170
name_op: OpTy<'tcx, Tag>,
7271
value_op: OpTy<'tcx, Tag>,
7372
) -> InterpResult<'tcx, i32> {
74-
let this = self.eval_context_mut();
73+
let mut this = self.eval_context_mut();
7574

7675
let name_ptr = this.read_scalar(name_op)?.not_undef()?;
7776
let value_ptr = this.read_scalar(value_op)?.not_undef()?;
78-
let value = this.memory.read_c_str(value_ptr)?;
77+
let value = this.read_os_str_from_c_str(value_ptr)?;
7978
let mut new = None;
8079
if !this.is_null(name_ptr)? {
81-
let name = this.memory.read_c_str(name_ptr)?;
82-
if !name.is_empty() && !name.contains(&b'=') {
80+
let name = this.read_os_str_from_c_str(name_ptr)?;
81+
if !name.is_empty() && !name.to_string_lossy().contains('=') {
8382
new = Some((name.to_owned(), value.to_owned()));
8483
}
8584
}
8685
if let Some((name, value)) = new {
87-
let var_ptr = alloc_env_var(&name, &value, &mut this.memory);
86+
let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this);
8887
if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) {
8988
this.memory
9089
.deallocate(var, None, MiriMemoryKind::Env.into())?;
@@ -101,8 +100,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
101100
let name_ptr = this.read_scalar(name_op)?.not_undef()?;
102101
let mut success = None;
103102
if !this.is_null(name_ptr)? {
104-
let name = this.memory.read_c_str(name_ptr)?.to_owned();
105-
if !name.is_empty() && !name.contains(&b'=') {
103+
let name = this.read_os_str_from_c_str(name_ptr)?.to_owned();
104+
if !name.is_empty() && !name.to_string_lossy().contains('=') {
106105
success = Some(this.machine.env_vars.map.remove(&name));
107106
}
108107
}

src/shims/foreign_items.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,10 +956,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
956956
this.write_null(dest)?;
957957
}
958958
"GetEnvironmentVariableW" => {
959+
// args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars)
960+
// args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars)
961+
// lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string.
962+
// Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator.
963+
// Return 0 upon failure.
964+
959965
// This is not the env var you are looking for.
960966
this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND
961967
this.write_null(dest)?;
962968
}
969+
"SetEnvironmentVariableW" => {
970+
// args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars)
971+
// args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars)
972+
// Return nonzero if success, else return 0.
973+
throw_unsup_format!("can't set environment variable on Windows");
974+
}
963975
"GetCommandLineW" => {
964976
this.write_scalar(
965977
this.machine.cmd_line.expect("machine must be initialized"),

0 commit comments

Comments
 (0)