support current_exe on macOS, and fix write_os_str length logic
This commit is contained in:
parent
f633537f3e
commit
61be3bae40
@ -18,11 +18,11 @@ fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 {
|
|||||||
if success {
|
if success {
|
||||||
// If the function succeeds, the return value is the number of characters stored in the target buffer,
|
// If the function succeeds, the return value is the number of characters stored in the target buffer,
|
||||||
// not including the terminating null character.
|
// not including the terminating null character.
|
||||||
u32::try_from(len).unwrap()
|
u32::try_from(len.checked_sub(1).unwrap()).unwrap()
|
||||||
} else {
|
} else {
|
||||||
// If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters,
|
// 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.
|
// required to hold the string and its terminating null character.
|
||||||
u32::try_from(len.checked_add(1).unwrap()).unwrap()
|
u32::try_from(len).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ pub fn u16vec_to_osstring<'tcx>(u16_vec: Vec<u16>) -> InterpResult<'tcx, OsStrin
|
|||||||
/// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying
|
/// the Unix 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
|
/// 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
|
/// terminator. It returns `Ok((true, length))` if the writing process was successful. The
|
||||||
/// string length returned does not include the null terminator.
|
/// 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,
|
||||||
@ -103,7 +103,8 @@ fn write_os_str_to_c_str(
|
|||||||
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
|
// 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.
|
// terminator to memory using the `ptr` pointer would cause an out-of-bounds access.
|
||||||
let string_length = u64::try_from(bytes.len()).unwrap();
|
let string_length = u64::try_from(bytes.len()).unwrap();
|
||||||
if size <= string_length {
|
let string_length = string_length.checked_add(1).unwrap();
|
||||||
|
if size < string_length {
|
||||||
return Ok((false, string_length));
|
return Ok((false, string_length));
|
||||||
}
|
}
|
||||||
self.eval_context_mut()
|
self.eval_context_mut()
|
||||||
@ -115,7 +116,8 @@ fn write_os_str_to_c_str(
|
|||||||
/// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying
|
/// 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
|
/// 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
|
/// terminator. It returns `Ok((true, length))` if the writing process was successful. The
|
||||||
/// string length returned does not include the null terminator.
|
/// string length returned does include the null terminator. Length is measured in units of
|
||||||
|
/// `u16.`
|
||||||
fn write_os_str_to_wide_str(
|
fn write_os_str_to_wide_str(
|
||||||
&mut self,
|
&mut self,
|
||||||
os_str: &OsStr,
|
os_str: &OsStr,
|
||||||
@ -157,7 +159,7 @@ fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec<u16>> {
|
|||||||
alloc
|
alloc
|
||||||
.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar).into())?;
|
.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar).into())?;
|
||||||
}
|
}
|
||||||
Ok((true, string_length - 1))
|
Ok((true, string_length))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
|
@ -1380,11 +1380,12 @@ fn macos_readdir_r(
|
|||||||
let name_place = this.mplace_field(&entry_place, 5)?;
|
let name_place = this.mplace_field(&entry_place, 5)?;
|
||||||
|
|
||||||
let file_name = dir_entry.file_name(); // not a Path as there are no separators!
|
let file_name = dir_entry.file_name(); // not a Path as there are no separators!
|
||||||
let (name_fits, file_name_len) = this.write_os_str_to_c_str(
|
let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str(
|
||||||
&file_name,
|
&file_name,
|
||||||
name_place.ptr,
|
name_place.ptr,
|
||||||
name_place.layout.size.bytes(),
|
name_place.layout.size.bytes(),
|
||||||
)?;
|
)?;
|
||||||
|
let file_name_len = file_name_buf_len.checked_sub(1).unwrap();
|
||||||
if !name_fits {
|
if !name_fits {
|
||||||
throw_unsup_format!(
|
throw_unsup_format!(
|
||||||
"a directory entry had a name too large to fit in libc::dirent"
|
"a directory entry had a name too large to fit in libc::dirent"
|
||||||
|
@ -117,6 +117,33 @@ fn emulate_foreign_item_by_name(
|
|||||||
dest,
|
dest,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
"_NSGetExecutablePath" => {
|
||||||
|
let [buf, bufsize] =
|
||||||
|
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
|
this.check_no_isolation("`_NSGetExecutablePath`")?;
|
||||||
|
|
||||||
|
let buf_ptr = this.read_pointer(buf)?;
|
||||||
|
let bufsize = this.deref_operand(bufsize)?;
|
||||||
|
|
||||||
|
// Using the host current_exe is a bit off, but consistent with Linux
|
||||||
|
// (where stdlib reads /proc/self/exe).
|
||||||
|
let path = std::env::current_exe().unwrap();
|
||||||
|
let (written, size_needed) = this.write_path_to_c_str(
|
||||||
|
&path,
|
||||||
|
buf_ptr,
|
||||||
|
this.read_scalar(&bufsize.into())?.to_u32()?.into(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if written {
|
||||||
|
this.write_null(dest)?;
|
||||||
|
} else {
|
||||||
|
this.write_scalar(
|
||||||
|
Scalar::from_u32(size_needed.try_into().unwrap()),
|
||||||
|
&bufsize.into(),
|
||||||
|
)?;
|
||||||
|
this.write_int(-1, dest)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Thread-local storage
|
// Thread-local storage
|
||||||
"_tlv_atexit" => {
|
"_tlv_atexit" => {
|
||||||
|
8
tests/pass/current_exe.rs
Normal file
8
tests/pass/current_exe.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
//@ignore-target-windows
|
||||||
|
//@compile-flags: -Zmiri-disable-isolation
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// The actual value we get is a bit odd: we get the Miri binary that interprets us.
|
||||||
|
env::current_exe().unwrap();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user