- os_str: &OsStr,
- scalar: Scalar<Tag>,
- size: u64,
- ) -> InterpResult<'tcx, (bool, u64)> {
- #[cfg(unix)]
- fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> {
- Ok(std::os::unix::ffi::OsStrExt::as_bytes(os_str))
- }
- #[cfg(not(unix))]
- fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> {
- // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the
- // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually
- // valid.
- os_str
- .to_str()
- .map(|s| s.as_bytes())
- .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into())
- }
-
- let bytes = os_str_to_bytes(os_str)?;
- // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
- // terminator to memory using the `ptr` pointer would cause an out-of-bounds access.
- let string_length = u64::try_from(bytes.len()).unwrap();
- if size <= string_length {
- return Ok((false, string_length));
- }
- self.eval_context_mut()
- .memory
- .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?;
- Ok((true, string_length))
- }
-
- /// Write a Path to the machine memory, adjusting path separators if needed.
- fn write_path_to_c_str(
- &mut self,
- path: &Path,
- scalar: Scalar<Tag>,
- size: u64,
- ) -> InterpResult<'tcx, (bool, u64)> {
- let os_str = path.as_os_str();
- self.write_os_str_to_c_str(os_str, scalar, size)
- }
-
- /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what
- /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying
- /// to write if `size` is not large enough to fit the contents of `os_string` plus a null
- /// terminator. It returns `Ok((true, length))` if the writing process was successful. The
- /// string length returned does not include the null terminator.
- fn write_os_str_to_wide_str(
- &mut self,
- os_str: &OsStr,
- mplace: MPlaceTy<'tcx, Tag>,
- size: u64,
- ) -> InterpResult<'tcx, (bool, u64)> {
- #[cfg(windows)]
- fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec<u16>> {
- Ok(std::os::windows::ffi::OsStrExt::encode_wide(os_str).collect())
- }
- #[cfg(not(windows))]
- fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec<u16>> {
- // On non-Windows platforms the best we can do to transform Vec<u16> from/to OS strings is to do the
- // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually
- // valid.
- os_str
- .to_str()
- .map(|s| s.encode_utf16().collect())
- .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into())
- }
-
- let u16_vec = os_str_to_u16vec(os_str)?;
- // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required
- // 0x0000 terminator to memory would cause an out-of-bounds access.
- let string_length = u64::try_from(u16_vec.len()).unwrap();
- if size <= string_length {
- return Ok((false, string_length));
- }
-