diff --git a/src/shims/env.rs b/src/shims/env.rs index dfbeabf2a12b..350d76bc9dac 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -125,7 +125,7 @@ fn GetEnvironmentVariableW( let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; // `buf_size` represents the size in characters. let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); - HowWasBufferSize(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) + windows_check_buffer_size(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) } None => { let envvar_not_found = this.eval_windows("ERROR_ENVVAR_NOT_FOUND")?; @@ -317,7 +317,7 @@ fn GetCurrentDirectoryW( // If we cannot get the current directory, we return 0 match env::current_dir() { Ok(cwd) => - return Ok(HowWasBufferSize(this.write_path_to_wide_str(&cwd, buf, size)?)), + return Ok(windows_check_buffer_size(this.write_path_to_wide_str(&cwd, buf, size)?)), Err(e) => this.set_last_error_from_io_error(e)?, } Ok(0) @@ -400,16 +400,17 @@ fn update_environ(&mut self) -> InterpResult<'tcx> { } } -// Local helper function to be used in Windows shims -#[allow(non_snake_case)] -fn HowWasBufferSize((success, len): (bool, u64)) -> u32 { +/// Check whether an operation that writes to a target buffer was successful. +/// Accordingly select return value. +/// Local helper function to be used in Windows shims. +fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { if success { - // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, + // If the function succeeds, the return value is the number of characters stored in the target buffer, // not including the terminating null character. u32::try_from(len).unwrap() } else { - // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, - // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. + // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters, + // required to hold the string and its terminating null character. u32::try_from(len.checked_add(1).unwrap()).unwrap() } } diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 59cedc6e9df7..74932ef6ca4e 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -13,6 +13,53 @@ use crate::*; +/// Represent how path separator conversion should be done. +enum Pathconversion { + HostToTarget, + TargetToHost, +} + +/// Perform path separator conversion if needed. +fn convert_path_separator<'a>( + os_str: &'a OsStr, + target_os: &str, + direction: Pathconversion, +) -> Cow<'a, OsStr> { + #[cfg(windows)] + return if target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(os_str) + } else { + // Unix target, Windows host. + let (from, to) = match direction { + Pathconversion::HostToTarget => ('\\', '/'), + Pathconversion::TargetToHost => ('/', '\\'), + }; + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + return if target_os == "windows" { + // Windows target, Unix host. + let (from, to) = match direction { + Pathconversion::HostToTarget => ('/', '\\'), + Pathconversion::TargetToHost => ('\\', '/'), + }; + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(os_str) + }; +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what @@ -177,9 +224,9 @@ fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, 'mir: 'a, { let this = self.eval_context_ref(); - let os_str: &'a OsStr = this.read_os_str_from_c_str(scalar)?; + let os_str = this.read_os_str_from_c_str(scalar)?; - Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, PathConversionDirection::TargetToHost) { + Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -188,9 +235,9 @@ fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. fn read_path_from_wide_str(&self, scalar: Scalar) -> InterpResult<'tcx, PathBuf> { let this = self.eval_context_ref(); - let os_str: OsString = this.read_os_str_from_wide_str(scalar)?; + let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, PathConversionDirection::TargetToHost))) + Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost))) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -202,7 +249,7 @@ fn write_path_to_c_str( size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, PathConversionDirection::HostToTarget); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -215,53 +262,7 @@ fn write_path_to_wide_str( size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, PathConversionDirection::HostToTarget); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } } - -enum PathConversionDirection { - HostToTarget, - TargetToHost, -} - -/// Perform path separator conversion if needed. -fn convert_path_separator<'a>( - os_str: &'a OsStr, - target_os: &str, - direction: PathConversionDirection, -) -> Cow<'a, OsStr> { - #[cfg(windows)] - return if target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(os_str) - } else { - // Unix target, Windows host. - let (from, to) = match direction { - PathConversionDirection::HostToTarget => ('\\', '/'), - PathConversionDirection::TargetToHost => ('/', '\\'), - }; - let converted = os_str - .encode_wide() - .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_wide(&converted)) - }; - #[cfg(unix)] - return if target_os == "windows" { - // Windows target, Unix host. - let (from, to) = match direction { - PathConversionDirection::HostToTarget => ('/', '\\'), - PathConversionDirection::TargetToHost => ('\\', '/'), - }; - let converted = os_str - .as_bytes() - .iter() - .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_vec(converted)) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(os_str) - }; -}