make the obsucre truncating variant of this.write_os_str_to_wide_str a non-default function
This commit is contained in:
parent
00acfabcee
commit
ccb43b6a95
3 changed files with 52 additions and 51 deletions
|
@ -178,7 +178,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
&var,
|
&var,
|
||||||
buf_ptr,
|
buf_ptr,
|
||||||
buf_size.into(),
|
buf_size.into(),
|
||||||
/*truncate*/ false,
|
|
||||||
)?))
|
)?))
|
||||||
// This can in fact return 0. It is up to the caller to set last_error to 0
|
// This can in fact return 0. It is up to the caller to set last_error to 0
|
||||||
// beforehand and check it afterwards to exclude that case.
|
// beforehand and check it afterwards to exclude that case.
|
||||||
|
@ -380,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
// This can in fact return 0. It is up to the caller to set last_error to 0
|
// This can in fact return 0. It is up to the caller to set last_error to 0
|
||||||
// beforehand and check it afterwards to exclude that case.
|
// beforehand and check it afterwards to exclude that case.
|
||||||
return Ok(Scalar::from_u32(windows_check_buffer_size(
|
return Ok(Scalar::from_u32(windows_check_buffer_size(
|
||||||
this.write_path_to_wide_str(&cwd, buf, size, /*truncate*/ false)?,
|
this.write_path_to_wide_str(&cwd, buf, size)?,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Err(e) => this.set_last_error_from_io_error(e.kind())?,
|
Err(e) => this.set_last_error_from_io_error(e.kind())?,
|
||||||
|
@ -535,12 +534,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
};
|
};
|
||||||
// Of course we cannot use `windows_check_buffer_size` here since this uses
|
// Of course we cannot use `windows_check_buffer_size` here since this uses
|
||||||
// a different method for dealing with a too-small buffer than the other functions...
|
// a different method for dealing with a too-small buffer than the other functions...
|
||||||
let (success, len) = this.write_path_to_wide_str(
|
let (success, len) = this.write_path_to_wide_str(home, buf, size_avail.into())?;
|
||||||
home,
|
|
||||||
buf,
|
|
||||||
size_avail.into(),
|
|
||||||
/*truncate*/ false,
|
|
||||||
)?;
|
|
||||||
// The Windows docs just say that this is written on failure. But std
|
// The Windows docs just say that this is written on failure. But std
|
||||||
// seems to rely on it always being written.
|
// seems to rely on it always being written.
|
||||||
this.write_scalar(Scalar::from_u32(len.try_into().unwrap()), &size)?;
|
this.write_scalar(Scalar::from_u32(len.try_into().unwrap()), &size)?;
|
||||||
|
|
|
@ -72,11 +72,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
u16vec_to_osstring(u16_vec)
|
u16vec_to_osstring(u16_vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what
|
/// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what the
|
||||||
/// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying
|
/// Unix APIs usually handle. Returns `(success, full_len)`, where length includes the null
|
||||||
/// to write if `size` is not large enough to fit the contents of `os_string` plus a null
|
/// terminator. On failure, nothing is written.
|
||||||
/// terminator. It returns `Ok((true, length))` if the writing process was successful. The
|
|
||||||
/// string length returned does include the null terminator.
|
|
||||||
fn write_os_str_to_c_str(
|
fn write_os_str_to_c_str(
|
||||||
&mut self,
|
&mut self,
|
||||||
os_str: &OsStr,
|
os_str: &OsStr,
|
||||||
|
@ -87,19 +85,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
self.eval_context_mut().write_c_str(bytes, ptr, size)
|
self.eval_context_mut().write_c_str(bytes, ptr, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the
|
/// Internal helper to share code between `write_os_str_to_wide_str` and
|
||||||
/// Windows APIs usually handle.
|
/// `write_os_str_to_wide_str_truncated`.
|
||||||
///
|
fn write_os_str_to_wide_str_helper(
|
||||||
/// If `truncate == false` (the usual mode of operation), 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 include the null terminator. Length is
|
|
||||||
/// measured in units of `u16.`
|
|
||||||
///
|
|
||||||
/// If `truncate == true`, then in case `size` is not large enough it *will* write the first
|
|
||||||
/// `size.saturating_sub(1)` many items, followed by a null terminator (if `size > 0`).
|
|
||||||
/// The return value is still `(false, length)` in that case.
|
|
||||||
fn write_os_str_to_wide_str(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
os_str: &OsStr,
|
os_str: &OsStr,
|
||||||
ptr: Pointer<Option<Provenance>>,
|
ptr: Pointer<Option<Provenance>>,
|
||||||
|
@ -133,6 +121,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
Ok((written, size_needed))
|
Ok((written, size_needed))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the
|
||||||
|
/// Windows APIs usually handle. Returns `(success, full_len)`, where length is measured
|
||||||
|
/// in units of `u16` and includes the null terminator. On failure, nothing is written.
|
||||||
|
fn write_os_str_to_wide_str(
|
||||||
|
&mut self,
|
||||||
|
os_str: &OsStr,
|
||||||
|
ptr: Pointer<Option<Provenance>>,
|
||||||
|
size: u64,
|
||||||
|
) -> InterpResult<'tcx, (bool, u64)> {
|
||||||
|
self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like `write_os_str_to_wide_str`, but on failure as much as possible is written into
|
||||||
|
/// the buffer (always with a null terminator).
|
||||||
|
fn write_os_str_to_wide_str_truncated(
|
||||||
|
&mut self,
|
||||||
|
os_str: &OsStr,
|
||||||
|
ptr: Pointer<Option<Provenance>>,
|
||||||
|
size: u64,
|
||||||
|
) -> InterpResult<'tcx, (bool, u64)> {
|
||||||
|
self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ true)
|
||||||
|
}
|
||||||
|
|
||||||
/// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.
|
/// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.
|
||||||
fn alloc_os_str_as_c_str(
|
fn alloc_os_str_as_c_str(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -160,9 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
|
|
||||||
let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u16, size);
|
let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u16, size);
|
||||||
let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
|
let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
|
||||||
let (written, _) = self
|
let (written, _) = self.write_os_str_to_wide_str(os_str, arg_place.ptr(), size).unwrap();
|
||||||
.write_os_str_to_wide_str(os_str, arg_place.ptr(), size, /*truncate*/ false)
|
|
||||||
.unwrap();
|
|
||||||
assert!(written);
|
assert!(written);
|
||||||
Ok(arg_place.ptr())
|
Ok(arg_place.ptr())
|
||||||
}
|
}
|
||||||
|
@ -217,12 +226,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
path: &Path,
|
path: &Path,
|
||||||
ptr: Pointer<Option<Provenance>>,
|
ptr: Pointer<Option<Provenance>>,
|
||||||
size: u64,
|
size: u64,
|
||||||
truncate: bool,
|
|
||||||
) -> InterpResult<'tcx, (bool, u64)> {
|
) -> InterpResult<'tcx, (bool, u64)> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
let os_str =
|
let os_str =
|
||||||
this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
|
this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
|
||||||
this.write_os_str_to_wide_str(&os_str, ptr, size, truncate)
|
this.write_os_str_to_wide_str(&os_str, ptr, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write a Path to the machine memory (as a null-terminated sequence of `u16`s),
|
||||||
|
/// adjusting path separators if needed.
|
||||||
|
fn write_path_to_wide_str_truncated(
|
||||||
|
&mut self,
|
||||||
|
path: &Path,
|
||||||
|
ptr: Pointer<Option<Provenance>>,
|
||||||
|
size: u64,
|
||||||
|
) -> InterpResult<'tcx, (bool, u64)> {
|
||||||
|
let this = self.eval_context_mut();
|
||||||
|
let os_str =
|
||||||
|
this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
|
||||||
|
this.write_os_str_to_wide_str_truncated(&os_str, ptr, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate enough memory to store a Path as a null-terminated sequence of bytes,
|
/// Allocate enough memory to store a Path as a null-terminated sequence of bytes,
|
||||||
|
|
|
@ -232,12 +232,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
Ok(abs_filename) => {
|
Ok(abs_filename) => {
|
||||||
Scalar::from_u32(helpers::windows_check_buffer_size(
|
Scalar::from_u32(helpers::windows_check_buffer_size(
|
||||||
this.write_path_to_wide_str(
|
this.write_path_to_wide_str(&abs_filename, buffer, size.into())?,
|
||||||
&abs_filename,
|
|
||||||
buffer,
|
|
||||||
size.into(),
|
|
||||||
/*truncate*/ false,
|
|
||||||
)?,
|
|
||||||
))
|
))
|
||||||
// This can in fact return 0. It is up to the caller to set last_error to 0
|
// This can in fact return 0. It is up to the caller to set last_error to 0
|
||||||
// beforehand and check it afterwards to exclude that case.
|
// beforehand and check it afterwards to exclude that case.
|
||||||
|
@ -608,15 +603,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
|
|
||||||
// Using the host current_exe is a bit off, but consistent with Linux
|
// Using the host current_exe is a bit off, but consistent with Linux
|
||||||
// (where stdlib reads /proc/self/exe).
|
// (where stdlib reads /proc/self/exe).
|
||||||
// Unfortunately this Windows function has a crazy behavior so we can't just use
|
|
||||||
// `write_path_to_wide_str`...
|
|
||||||
let path = std::env::current_exe().unwrap();
|
let path = std::env::current_exe().unwrap();
|
||||||
let (all_written, size_needed) = this.write_path_to_wide_str(
|
let (all_written, size_needed) =
|
||||||
&path,
|
this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
|
||||||
filename,
|
|
||||||
size.into(),
|
|
||||||
/*truncate*/ true,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if all_written {
|
if all_written {
|
||||||
// If the function succeeds, the return value is the length of the string that
|
// If the function succeeds, the return value is the length of the string that
|
||||||
|
@ -656,12 +645,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
Some(err) => format!("{err}"),
|
Some(err) => format!("{err}"),
|
||||||
None => format!("<unknown error in FormatMessageW: {message_id}>"),
|
None => format!("<unknown error in FormatMessageW: {message_id}>"),
|
||||||
};
|
};
|
||||||
let (complete, length) = this.write_os_str_to_wide_str(
|
let (complete, length) =
|
||||||
OsStr::new(&formatted),
|
this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
|
||||||
buffer,
|
|
||||||
size.into(),
|
|
||||||
/*truncate*/ false,
|
|
||||||
)?;
|
|
||||||
if !complete {
|
if !complete {
|
||||||
// The API docs don't say what happens when the buffer is not big enough...
|
// The API docs don't say what happens when the buffer is not big enough...
|
||||||
// Let's just bail.
|
// Let's just bail.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue