Skip to content

Commit 2051805

Browse files
committed
follow-up to reviews
1 parent cf5822a commit 2051805

File tree

2 files changed

+69
-50
lines changed

2 files changed

+69
-50
lines changed

src/shims/env.rs

Lines changed: 65 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![allow(non_snake_case)]
2+
13
use std::ffi::{OsString, OsStr};
24
use std::env;
35
use std::convert::TryFrom;
@@ -26,7 +28,7 @@ impl<'tcx> EnvVars<'tcx> {
2628
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
2729
mut excluded_env_vars: Vec<String>,
2830
) -> InterpResult<'tcx> {
29-
if ecx.tcx.sess.target.target.target_os.to_lowercase() == "windows" {
31+
if ecx.tcx.sess.target.target.target_os == "windows" {
3032
// Exclude `TERM` var to avoid terminfo trying to open the termcap file.
3133
excluded_env_vars.push("TERM".to_owned());
3234
}
@@ -46,7 +48,7 @@ impl<'tcx> EnvVars<'tcx> {
4648
ecx.update_environ()
4749
}
4850

49-
pub(super) fn values(&self) -> InterpResult<'tcx, Values<'_, OsString, Pointer<Tag>>> {
51+
fn values(&self) -> InterpResult<'tcx, Values<'_, OsString, Pointer<Tag>>> {
5052
Ok(self.map.values())
5153
}
5254
}
@@ -73,6 +75,28 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>(
7375
Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into()))
7476
}
7577

78+
fn alloc_env_var_as_c_str<'mir, 'tcx>(
79+
name: &OsStr,
80+
value: &OsStr,
81+
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
82+
) -> InterpResult<'tcx, Pointer<Tag>> {
83+
let mut name_osstring = name.to_os_string();
84+
name_osstring.push("=");
85+
name_osstring.push(value);
86+
Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into()))
87+
}
88+
89+
fn alloc_env_var_as_wide_str<'mir, 'tcx>(
90+
name: &OsStr,
91+
value: &OsStr,
92+
ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
93+
) -> InterpResult<'tcx, Pointer<Tag>> {
94+
let mut name_osstring = name.to_os_string();
95+
name_osstring.push("=");
96+
name_osstring.push(value);
97+
Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into()))
98+
}
99+
76100
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
77101
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
78102
fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar<Tag>> {
@@ -91,7 +115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
91115
})
92116
}
93117

94-
fn getenvironmentvariablew(
118+
fn GetEnvironmentVariableW(
95119
&mut self,
96120
name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName
97121
buf_op: OpTy<'tcx, Tag>, // LPWSTR lpBuffer
@@ -110,21 +134,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
110134
let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?);
111135

112136
let var_size = u64::try_from(this.read_os_str_from_wide_str(var_ptr)?.len()).unwrap();
113-
let buf_size = u64::try_from(this.read_scalar(size_op)?.to_i32()?).unwrap();
137+
// `buf_size` represent size in characters.
138+
let buf_size = u64::try_from(this.read_scalar(size_op)?.to_u32()?).unwrap();
114139
let return_val = if var_size.checked_add(1).unwrap() > buf_size {
115140
// If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters,
116141
// required to hold the string and its terminating null character and the contents of lpBuffer are undefined.
117142
var_size + 1
118143
} else {
119144
let buf_ptr = this.read_scalar(buf_op)?.not_undef()?;
120-
for i in 0..var_size {
121-
this.memory.copy(
122-
this.force_ptr(var_ptr.ptr_offset(Size::from_bytes(i) * 2, this)?)?,
123-
this.force_ptr(buf_ptr.ptr_offset(Size::from_bytes(i) * 2, this)?)?,
124-
Size::from_bytes(2),
125-
true,
126-
)?;
127-
}
145+
let bytes_to_be_copied = var_size.checked_add(1).unwrap().checked_mul(2).unwrap();
146+
this.memory.copy(this.force_ptr(var_ptr)?, this.force_ptr(buf_ptr)?, Size::from_bytes(bytes_to_be_copied), true)?;
128147
// If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer,
129148
// not including the terminating null character.
130149
var_size
@@ -138,30 +157,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
138157
})
139158
}
140159

141-
fn getenvironmentstringsw(&mut self) -> InterpResult<'tcx, Scalar<Tag>> {
160+
fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Scalar<Tag>> {
142161
let this = self.eval_context_mut();
143162
this.assert_target_os("windows", "GetEnvironmentStringsW");
144163

145164
// Info on layout of environment blocks in Windows:
146165
// https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables
147166
let mut env_vars = std::ffi::OsString::new();
148167
for &item in this.machine.env_vars.values()? {
149-
let env_var = this.read_os_str_from_target_str(Scalar::from(item))?;
168+
let env_var = this.read_os_str_from_wide_str(Scalar::from(item))?;
150169
env_vars.push(env_var);
151170
env_vars.push("\0");
152171
}
172+
// Allocate environment block & Store environment variables to environment block.
173+
// Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`.
174+
let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::WinHeap.into());
153175

154-
// Allocate environment block
155-
let tcx = this.tcx;
156-
let env_block_size = env_vars.len().checked_add(1).unwrap();
157-
let env_block_type = tcx.mk_array(tcx.types.u16, u64::try_from(env_block_size).unwrap());
158-
let env_block_place = this.allocate(this.layout_of(env_block_type)?, MiriMemoryKind::WinHeap.into());
159-
160-
// Store environment variables to environment block
161-
// Final null terminator(block terminator) is pushed by `write_os_str_to_wide_str`
162-
this.write_os_str_to_wide_str(&env_vars, env_block_place, u64::try_from(env_block_size).unwrap())?;
176+
Ok(envblock_ptr.into())
177+
}
178+
179+
fn FreeEnvironmentStringsW(&mut self, env_block_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, bool> {
180+
let this = self.eval_context_mut();
181+
this.assert_target_os("windows", "FreeEnvironmentStringsW");
163182

164-
Ok(env_block_place.ptr)
183+
let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?;
184+
Ok(this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()).is_ok())
165185
}
166186

167187
fn setenv(
@@ -200,7 +220,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
200220
}
201221
}
202222

203-
fn setenvironmentvariablew(
223+
fn SetEnvironmentVariableW(
204224
&mut self,
205225
name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName,
206226
value_op: OpTy<'tcx, Tag>, // LPCWSTR lpValue,
@@ -211,32 +231,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
211231
let name_ptr = this.read_scalar(name_op)?.not_undef()?;
212232
let value_ptr = this.read_scalar(value_op)?.not_undef()?;
213233

214-
let mut new = None;
215-
if !this.is_null(name_ptr)? {
216-
let name = this.read_os_str_from_target_str(name_ptr)?;
217-
if this.is_null(value_ptr)? {
218-
// Delete environment variable `{name}`
219-
if let Some(var) = this.machine.env_vars.map.remove(&name) {
220-
this.memory.deallocate(var, None, MiriMemoryKind::Machine.into())?;
221-
this.update_environ()?;
222-
}
223-
return Ok(1); // return non-zero on success
224-
}
225-
if !name.is_empty() && !name.to_string_lossy().contains('=') {
226-
let value = this.read_os_str_from_target_str(value_ptr)?;
227-
new = Some((name.to_owned(), value.to_owned()));
228-
}
234+
if this.is_null(name_ptr)? {
235+
// ERROR CODE is not clearly explained in docs.. For now, throw UB instead.
236+
throw_ub_format!("Pointer to environment variable name is NULL");
229237
}
230-
if let Some((name, value)) = new {
231-
let var_ptr = alloc_env_var_as_target_str(&name, &value, &mut this)?;
238+
239+
let name = this.read_os_str_from_wide_str(name_ptr)?;
240+
if name.is_empty() {
241+
throw_unsup_format!("Environment variable name is an empty string");
242+
} else if name.to_string_lossy().contains('=') {
243+
throw_unsup_format!("Environment variable name contains '='");
244+
} else if this.is_null(value_ptr)? {
245+
// Delete environment variable `{name}`
246+
if let Some(var) = this.machine.env_vars.map.remove(&name) {
247+
this.memory.deallocate(var, None, MiriMemoryKind::Machine.into())?;
248+
this.update_environ()?;
249+
}
250+
Ok(1) // return non-zero on success
251+
} else {
252+
let value = this.read_os_str_from_wide_str(value_ptr)?;
253+
let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?;
232254
if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) {
233255
this.memory
234256
.deallocate(var, None, MiriMemoryKind::Machine.into())?;
235257
}
236258
this.update_environ()?;
237259
Ok(1) // return non-zero on success
238-
} else {
239-
Ok(0)
240260
}
241261
}
242262

@@ -248,7 +268,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
248268
let name_ptr = this.read_scalar(name_op)?.not_undef()?;
249269
let mut success = None;
250270
if !this.is_null(name_ptr)? {
251-
let name = this.read_os_str_from_target_str(name_ptr)?.to_owned();
271+
let name = this.read_os_str_from_c_str(name_ptr)?.to_owned();
252272
if !name.is_empty() && !name.to_string_lossy().contains('=') {
253273
success = Some(this.machine.env_vars.map.remove(&name));
254274
}

src/shims/foreign_items/windows.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
2323

2424
// Environment related shims
2525
"GetEnvironmentVariableW" => {
26-
let result = this.getenvironmentvariablew(args[0], args[1], args[2])?;
26+
let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?;
2727
this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?;
2828
}
2929

3030
"SetEnvironmentVariableW" => {
31-
let result = this.setenvironmentvariablew(args[0], args[1])?;
31+
let result = this.SetEnvironmentVariableW(args[0], args[1])?;
3232
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
3333
}
3434

3535
"GetEnvironmentStringsW" => {
36-
let result = this.getenvironmentstringsw()?;
36+
let result = this.GetEnvironmentStringsW()?;
3737
// If the function succeeds, the return value is a pointer to the environment block of the current process.
3838
this.write_scalar(result, dest)?;
3939
}
4040

4141
"FreeEnvironmentStringsW" => {
42-
let old_vars_ptr = this.read_scalar(args[0])?.not_undef()?;
43-
let result = this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::WinHeap.into()).is_ok();
42+
let result = this.FreeEnvironmentStringsW(args[0])?;
4443
// If the function succeeds, the return value is nonzero.
4544
this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
4645
}

0 commit comments

Comments
 (0)