Skip to content

Commit ad8c784

Browse files
committed
Return length from write_os_str_to_c_str
1 parent 9e03b41 commit ad8c784

File tree

3 files changed

+33
-38
lines changed

3 files changed

+33
-38
lines changed

src/helpers.rs

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -474,35 +474,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
474474
}
475475

476476
/// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what
477-
/// the Unix APIs usually handle. This function returns `Ok(false)` without trying to write if
478-
/// `size` is not large enough to fit the contents of `os_string` plus a null terminator. It
479-
/// returns `Ok(true)` if the writing process was successful.
477+
/// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying
478+
/// to write if `size` is not large enough to fit the contents of `os_string` plus a null
479+
/// terminator. It returns `Ok((true, length))` if the writing process was successful. The
480+
/// string length returned does not include the null terminator.
480481
fn write_os_str_to_c_str(
481482
&mut self,
482483
os_str: &OsStr,
483484
scalar: Scalar<Tag>,
484485
size: u64,
485-
) -> InterpResult<'tcx, bool> {
486+
) -> InterpResult<'tcx, (bool, u64)> {
487+
#[cfg(target_os = "unix")]
488+
fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> {
489+
std::os::unix::ffi::OsStringExt::into_bytes(os_str)
490+
}
491+
#[cfg(not(target_os = "unix"))]
492+
fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> {
493+
// On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the
494+
// intermediate transformation into strings. Which invalidates non-utf8 paths that are actually
495+
// valid.
496+
os_str
497+
.to_str()
498+
.map(|s| s.as_bytes())
499+
.ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into())
500+
}
501+
486502
let bytes = os_str_to_bytes(os_str)?;
487503
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
488504
// terminator to memory using the `ptr` pointer would cause an out-of-bounds access.
489-
if size <= bytes.len() as u64 {
490-
return Ok(false);
505+
let string_length = bytes.len() as u64;
506+
if size <= string_length {
507+
return Ok((false, string_length));
491508
}
492509
self.eval_context_mut()
493510
.memory
494511
.write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?;
495-
Ok(true)
496-
}
497-
498-
/// Helper function to determine how long an OsStr would be as a C string, not including the
499-
/// null terminator.
500-
fn os_str_length_as_c_str(
501-
&mut self,
502-
os_str: &OsStr,
503-
) -> InterpResult<'tcx, usize> {
504-
let bytes = os_str_to_bytes(os_str)?;
505-
Ok(bytes.len())
512+
Ok((true, string_length))
506513
}
507514

508515
fn alloc_os_str_as_c_str(
@@ -520,22 +527,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
520527
}
521528
}
522529

523-
#[cfg(target_os = "unix")]
524-
fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> {
525-
std::os::unix::ffi::OsStringExt::into_bytes(os_str)
526-
}
527-
528-
#[cfg(not(target_os = "unix"))]
529-
fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> {
530-
// On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the
531-
// intermediate transformation into strings. Which invalidates non-utf8 paths that are actually
532-
// valid.
533-
os_str
534-
.to_str()
535-
.map(|s| s.as_bytes())
536-
.ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into())
537-
}
538-
539530
pub fn immty_from_int_checked<'tcx>(
540531
int: impl Into<i128>,
541532
layout: TyLayout<'tcx>,

src/shims/env.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
124124
// If we cannot get the current directory, we return null
125125
match env::current_dir() {
126126
Ok(cwd) => {
127-
if this.write_os_str_to_c_str(&OsString::from(cwd), buf, size)? {
127+
if this.write_os_str_to_c_str(&OsString::from(cwd), buf, size)?.0 {
128128
return Ok(buf);
129129
}
130130
let erange = this.eval_libc("ERANGE")?;

src/shims/fs.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
906906
let name_place = this.mplace_field(entry_place, 4)?;
907907

908908
let file_name = dir_entry.file_name();
909-
let name_fits = this.write_os_str_to_c_str(&file_name, name_place.ptr, name_place.layout.size.bytes())?;
909+
let (name_fits, _) = this.write_os_str_to_c_str(
910+
&file_name, name_place.ptr,
911+
name_place.layout.size.bytes(),
912+
)?;
910913
if !name_fits {
911914
throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent64");
912915
}
@@ -990,7 +993,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
990993
let name_place = this.mplace_field(entry_place, 5)?;
991994

992995
let file_name = dir_entry.file_name();
993-
let name_fits = this.write_os_str_to_c_str(&file_name, name_place.ptr, name_place.layout.size.bytes())?;
996+
let (name_fits, file_name_len) = this.write_os_str_to_c_str(
997+
&file_name, name_place.ptr,
998+
name_place.layout.size.bytes(),
999+
)?;
9941000
if !name_fits {
9951001
throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent");
9961002
}
@@ -1008,8 +1014,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
10081014
#[cfg(not(unix))]
10091015
let ino = 0;
10101016

1011-
let file_name_len = this.os_str_length_as_c_str(&file_name)? as u128;
1012-
10131017
let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128;
10141018

10151019
let imms = [

0 commit comments

Comments
 (0)