Skip to content

Commit ccb43b6

Browse files
committed
make the obsucre truncating variant of this.write_os_str_to_wide_str a non-default function
1 parent 00acfab commit ccb43b6

File tree

3 files changed

+52
-51
lines changed

3 files changed

+52
-51
lines changed

src/tools/miri/src/shims/env.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
178178
&var,
179179
buf_ptr,
180180
buf_size.into(),
181-
/*truncate*/ false,
182181
)?))
183182
// This can in fact return 0. It is up to the caller to set last_error to 0
184183
// beforehand and check it afterwards to exclude that case.
@@ -380,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
380379
// This can in fact return 0. It is up to the caller to set last_error to 0
381380
// beforehand and check it afterwards to exclude that case.
382381
return Ok(Scalar::from_u32(windows_check_buffer_size(
383-
this.write_path_to_wide_str(&cwd, buf, size, /*truncate*/ false)?,
382+
this.write_path_to_wide_str(&cwd, buf, size)?,
384383
)));
385384
}
386385
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> {
535534
};
536535
// Of course we cannot use `windows_check_buffer_size` here since this uses
537536
// a different method for dealing with a too-small buffer than the other functions...
538-
let (success, len) = this.write_path_to_wide_str(
539-
home,
540-
buf,
541-
size_avail.into(),
542-
/*truncate*/ false,
543-
)?;
537+
let (success, len) = this.write_path_to_wide_str(home, buf, size_avail.into())?;
544538
// The Windows docs just say that this is written on failure. But std
545539
// seems to rely on it always being written.
546540
this.write_scalar(Scalar::from_u32(len.try_into().unwrap()), &size)?;

src/tools/miri/src/shims/os_str.rs

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
7272
u16vec_to_osstring(u16_vec)
7373
}
7474

75-
/// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what
76-
/// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying
77-
/// to write if `size` is not large enough to fit the contents of `os_string` plus a null
78-
/// terminator. It returns `Ok((true, length))` if the writing process was successful. The
79-
/// string length returned does include the null terminator.
75+
/// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what the
76+
/// Unix APIs usually handle. Returns `(success, full_len)`, where length includes the null
77+
/// terminator. On failure, nothing is written.
8078
fn write_os_str_to_c_str(
8179
&mut self,
8280
os_str: &OsStr,
@@ -87,19 +85,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
8785
self.eval_context_mut().write_c_str(bytes, ptr, size)
8886
}
8987

90-
/// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the
91-
/// Windows APIs usually handle.
92-
///
93-
/// If `truncate == false` (the usual mode of operation), this function returns `Ok((false,
94-
/// length))` without trying to write if `size` is not large enough to fit the contents of
95-
/// `os_string` plus a null terminator. It returns `Ok((true, length))` if the writing process
96-
/// was successful. The string length returned does include the null terminator. Length is
97-
/// measured in units of `u16.`
98-
///
99-
/// If `truncate == true`, then in case `size` is not large enough it *will* write the first
100-
/// `size.saturating_sub(1)` many items, followed by a null terminator (if `size > 0`).
101-
/// The return value is still `(false, length)` in that case.
102-
fn write_os_str_to_wide_str(
88+
/// Internal helper to share code between `write_os_str_to_wide_str` and
89+
/// `write_os_str_to_wide_str_truncated`.
90+
fn write_os_str_to_wide_str_helper(
10391
&mut self,
10492
os_str: &OsStr,
10593
ptr: Pointer<Option<Provenance>>,
@@ -133,6 +121,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
133121
Ok((written, size_needed))
134122
}
135123

124+
/// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what the
125+
/// Windows APIs usually handle. Returns `(success, full_len)`, where length is measured
126+
/// in units of `u16` and includes the null terminator. On failure, nothing is written.
127+
fn write_os_str_to_wide_str(
128+
&mut self,
129+
os_str: &OsStr,
130+
ptr: Pointer<Option<Provenance>>,
131+
size: u64,
132+
) -> InterpResult<'tcx, (bool, u64)> {
133+
self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ false)
134+
}
135+
136+
/// Like `write_os_str_to_wide_str`, but on failure as much as possible is written into
137+
/// the buffer (always with a null terminator).
138+
fn write_os_str_to_wide_str_truncated(
139+
&mut self,
140+
os_str: &OsStr,
141+
ptr: Pointer<Option<Provenance>>,
142+
size: u64,
143+
) -> InterpResult<'tcx, (bool, u64)> {
144+
self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ true)
145+
}
146+
136147
/// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.
137148
fn alloc_os_str_as_c_str(
138149
&mut self,
@@ -160,9 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
160171

161172
let arg_type = Ty::new_array(this.tcx.tcx, this.tcx.types.u16, size);
162173
let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?;
163-
let (written, _) = self
164-
.write_os_str_to_wide_str(os_str, arg_place.ptr(), size, /*truncate*/ false)
165-
.unwrap();
174+
let (written, _) = self.write_os_str_to_wide_str(os_str, arg_place.ptr(), size).unwrap();
166175
assert!(written);
167176
Ok(arg_place.ptr())
168177
}
@@ -217,12 +226,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
217226
path: &Path,
218227
ptr: Pointer<Option<Provenance>>,
219228
size: u64,
220-
truncate: bool,
221229
) -> InterpResult<'tcx, (bool, u64)> {
222230
let this = self.eval_context_mut();
223231
let os_str =
224232
this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
225-
this.write_os_str_to_wide_str(&os_str, ptr, size, truncate)
233+
this.write_os_str_to_wide_str(&os_str, ptr, size)
234+
}
235+
236+
/// Write a Path to the machine memory (as a null-terminated sequence of `u16`s),
237+
/// adjusting path separators if needed.
238+
fn write_path_to_wide_str_truncated(
239+
&mut self,
240+
path: &Path,
241+
ptr: Pointer<Option<Provenance>>,
242+
size: u64,
243+
) -> InterpResult<'tcx, (bool, u64)> {
244+
let this = self.eval_context_mut();
245+
let os_str =
246+
this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
247+
this.write_os_str_to_wide_str_truncated(&os_str, ptr, size)
226248
}
227249

228250
/// Allocate enough memory to store a Path as a null-terminated sequence of bytes,

src/tools/miri/src/shims/windows/foreign_items.rs

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
232232
}
233233
Ok(abs_filename) => {
234234
Scalar::from_u32(helpers::windows_check_buffer_size(
235-
this.write_path_to_wide_str(
236-
&abs_filename,
237-
buffer,
238-
size.into(),
239-
/*truncate*/ false,
240-
)?,
235+
this.write_path_to_wide_str(&abs_filename, buffer, size.into())?,
241236
))
242237
// This can in fact return 0. It is up to the caller to set last_error to 0
243238
// beforehand and check it afterwards to exclude that case.
@@ -608,15 +603,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
608603

609604
// Using the host current_exe is a bit off, but consistent with Linux
610605
// (where stdlib reads /proc/self/exe).
611-
// Unfortunately this Windows function has a crazy behavior so we can't just use
612-
// `write_path_to_wide_str`...
613606
let path = std::env::current_exe().unwrap();
614-
let (all_written, size_needed) = this.write_path_to_wide_str(
615-
&path,
616-
filename,
617-
size.into(),
618-
/*truncate*/ true,
619-
)?;
607+
let (all_written, size_needed) =
608+
this.write_path_to_wide_str_truncated(&path, filename, size.into())?;
620609

621610
if all_written {
622611
// 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> {
656645
Some(err) => format!("{err}"),
657646
None => format!("<unknown error in FormatMessageW: {message_id}>"),
658647
};
659-
let (complete, length) = this.write_os_str_to_wide_str(
660-
OsStr::new(&formatted),
661-
buffer,
662-
size.into(),
663-
/*truncate*/ false,
664-
)?;
648+
let (complete, length) =
649+
this.write_os_str_to_wide_str(OsStr::new(&formatted), buffer, size.into())?;
665650
if !complete {
666651
// The API docs don't say what happens when the buffer is not big enough...
667652
// Let's just bail.

0 commit comments

Comments
 (0)