Skip to content

Commit e2a9c7b

Browse files
committed
Auto merge of #1266 - JOE1994:write_os_str_to_wide_str, r=RalfJung
Change helper fn 'write_os_str_to_wide_str' Helper fn `write_os_str_to_wide_str` now works on `Scalar<Tag>`, just like other **read/write os_str** helper functions. The 2nd commit contains some changes made to `src/shims/env.rs` in PR #1225, in order to keep it from bloating too much.
2 parents 0d0a457 + 07f7083 commit e2a9c7b

File tree

3 files changed

+44
-49
lines changed

3 files changed

+44
-49
lines changed

rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
a5fb9ae5b2ed3cb011ada9dc1e8633aa0927f279
1+
7b73d14b0b35e7b4f79f2d71dc1bbbab31698288

src/helpers.rs

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -463,18 +463,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
463463
}
464464
}
465465

466-
/// Dispatches to appropriate implementations for reading an OsString from Memory,
467-
/// depending on the interpretation target.
468-
/// FIXME: Use `Cow` to avoid copies
469-
fn read_os_str_from_target_str(&self, scalar: Scalar<Tag>) -> InterpResult<'tcx, OsString> {
470-
let target_os = self.eval_context_ref().tcx.sess.target.target.target_os.as_str();
471-
match target_os {
472-
"linux" | "macos" => self.read_os_str_from_c_str(scalar).map(|x| x.to_os_string()),
473-
"windows" => self.read_os_str_from_wide_str(scalar),
474-
unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported),
475-
}
476-
}
477-
478466
/// Helper function to read an OsString from a null-terminated sequence of bytes, which is what
479467
/// the Unix APIs usually handle.
480468
fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar<Tag>) -> InterpResult<'tcx, &'a OsStr>
@@ -567,7 +555,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
567555
fn write_os_str_to_wide_str(
568556
&mut self,
569557
os_str: &OsStr,
570-
mplace: MPlaceTy<'tcx, Tag>,
558+
scalar: Scalar<Tag>,
571559
size: u64,
572560
) -> InterpResult<'tcx, (bool, u64)> {
573561
#[cfg(windows)]
@@ -593,32 +581,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
593581
return Ok((false, string_length));
594582
}
595583

596-
let this = self.eval_context_mut();
597-
598584
// Store the UTF-16 string.
599-
let char_size = Size::from_bytes(2);
600-
for (idx, c) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() {
601-
let place = this.mplace_field(mplace, idx)?;
602-
this.write_scalar(Scalar::from_uint(c, char_size), place.into())?;
603-
}
585+
self.eval_context_mut()
586+
.memory
587+
.write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?;
604588
Ok((true, string_length))
605589
}
606590

607-
/// Dispatches to appropriate implementations for allocating & writing OsString in Memory,
608-
/// depending on the interpretation target.
609-
fn alloc_os_str_as_target_str(
610-
&mut self,
611-
os_str: &OsStr,
612-
memkind: MemoryKind<MiriMemoryKind>,
613-
) -> InterpResult<'tcx, Pointer<Tag>> {
614-
let target_os = self.eval_context_ref().tcx.sess.target.target.target_os.as_str();
615-
match target_os {
616-
"linux" | "macos" => Ok(self.alloc_os_str_as_c_str(os_str, memkind)),
617-
"windows" => Ok(self.alloc_os_str_as_wide_str(os_str, memkind)),
618-
unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported),
619-
}
620-
}
621-
622591
/// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.
623592
fn alloc_os_str_as_c_str(
624593
&mut self,
@@ -645,7 +614,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
645614

646615
let arg_type = this.tcx.mk_array(this.tcx.types.u16, size);
647616
let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind);
648-
assert!(self.write_os_str_to_wide_str(os_str, arg_place, size).unwrap().0);
617+
assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0);
649618
arg_place.ptr.assert_ptr()
650619
}
651620

src/shims/env.rs

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ impl<'tcx> EnvVars<'tcx> {
2626
excluded_env_vars: Vec<String>,
2727
) -> InterpResult<'tcx> {
2828
if ecx.machine.communicate {
29+
let target_os = ecx.tcx.sess.target.target.target_os.as_str();
2930
for (name, value) in env::vars() {
3031
if !excluded_env_vars.contains(&name) {
31-
let var_ptr =
32-
alloc_env_var_as_target_str(name.as_ref(), value.as_ref(), ecx)?;
32+
let var_ptr = match target_os {
33+
"linux" | "macos" => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?,
34+
"windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?,
35+
unsupported => throw_unsup_format!("environment support for target OS `{}` not yet available", unsupported),
36+
};
3337
ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr);
3438
}
3539
}
@@ -38,30 +42,41 @@ impl<'tcx> EnvVars<'tcx> {
3842
}
3943
}
4044

41-
fn alloc_env_var_as_target_str<'mir, 'tcx>(
45+
fn alloc_env_var_as_c_str<'mir, 'tcx>(
4246
name: &OsStr,
4347
value: &OsStr,
4448
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
4549
) -> InterpResult<'tcx, Pointer<Tag>> {
4650
let mut name_osstring = name.to_os_string();
4751
name_osstring.push("=");
4852
name_osstring.push(value);
49-
Ok(ecx.alloc_os_str_as_target_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())?)
53+
Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into()))
54+
}
55+
56+
fn alloc_env_var_as_wide_str<'mir, 'tcx>(
57+
name: &OsStr,
58+
value: &OsStr,
59+
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
60+
) -> InterpResult<'tcx, Pointer<Tag>> {
61+
let mut name_osstring = name.to_os_string();
62+
name_osstring.push("=");
63+
name_osstring.push(value);
64+
Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into()))
5065
}
5166

5267
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
5368
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
5469
fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar<Tag>> {
5570
let this = self.eval_context_mut();
56-
let target_os = this.tcx.sess.target.target.target_os.as_str();
57-
assert!(target_os == "linux" || target_os == "macos", "`{}` is only available for the UNIX target family");
71+
let target_os = &this.tcx.sess.target.target.target_os;
72+
assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family");
5873

5974
let name_ptr = this.read_scalar(name_op)?.not_undef()?;
6075
let name = this.read_os_str_from_c_str(name_ptr)?;
6176
Ok(match this.machine.env_vars.map.get(name) {
62-
// The offset is used to strip the "{name}=" part of the string.
6377
Some(var_ptr) => {
64-
Scalar::from(var_ptr.offset(Size::from_bytes(name.len()) + Size::from_bytes(1), this)?)
78+
// The offset is used to strip the "{name}=" part of the string.
79+
Scalar::from(var_ptr.offset(Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this)?)
6580
}
6681
None => Scalar::ptr_null(&*this.tcx),
6782
})
@@ -73,32 +88,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
7388
value_op: OpTy<'tcx, Tag>,
7489
) -> InterpResult<'tcx, i32> {
7590
let mut this = self.eval_context_mut();
91+
let target_os = &this.tcx.sess.target.target.target_os;
92+
assert!(target_os == "linux" || target_os == "macos", "`setenv` is only available for the UNIX target family");
7693

7794
let name_ptr = this.read_scalar(name_op)?.not_undef()?;
7895
let value_ptr = this.read_scalar(value_op)?.not_undef()?;
79-
let value = this.read_os_str_from_target_str(value_ptr)?;
96+
8097
let mut new = None;
8198
if !this.is_null(name_ptr)? {
82-
let name = this.read_os_str_from_target_str(name_ptr)?;
99+
let name = this.read_os_str_from_c_str(name_ptr)?;
83100
if !name.is_empty() && !name.to_string_lossy().contains('=') {
101+
let value = this.read_os_str_from_c_str(value_ptr)?;
84102
new = Some((name.to_owned(), value.to_owned()));
85103
}
86104
}
87105
if let Some((name, value)) = new {
88-
let var_ptr = alloc_env_var_as_target_str(&name, &value, &mut this)?;
106+
let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?;
89107
if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) {
90108
this.memory
91109
.deallocate(var, None, MiriMemoryKind::Machine.into())?;
92110
}
93111
this.update_environ()?;
94-
Ok(0)
112+
Ok(0) // return zero on success
95113
} else {
114+
// name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
115+
let einval = this.eval_libc("EINVAL")?;
116+
this.set_last_error(einval)?;
96117
Ok(-1)
97118
}
98119
}
99120

100121
fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
101122
let this = self.eval_context_mut();
123+
let target_os = &this.tcx.sess.target.target.target_os;
124+
assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family");
102125

103126
let name_ptr = this.read_scalar(name_op)?.not_undef()?;
104127
let mut success = None;
@@ -116,6 +139,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
116139
this.update_environ()?;
117140
Ok(0)
118141
} else {
142+
// name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
143+
let einval = this.eval_libc("EINVAL")?;
144+
this.set_last_error(einval)?;
119145
Ok(-1)
120146
}
121147
}

0 commit comments

Comments
 (0)