Auto merge of #1805 - RalfJung:c_str, r=RalfJung
stop relying on c_str/wide_str helpers in rustc This is a part of https://github.com/rust-lang/miri/pull/1804 that we can already do.
This commit is contained in:
commit
0d87afe5a5
@ -566,6 +566,51 @@ fn read_timespec(
|
||||
Duration::new(seconds, nanoseconds)
|
||||
})
|
||||
}
|
||||
|
||||
fn read_c_str<'a>(&'a self, sptr: Scalar<Tag>) -> InterpResult<'tcx, &'a [u8]>
|
||||
where
|
||||
'tcx: 'a,
|
||||
'mir: 'a,
|
||||
{
|
||||
let this = self.eval_context_ref();
|
||||
let size1 = Size::from_bytes(1);
|
||||
let ptr = this.force_ptr(sptr)?; // We need to read at least 1 byte, so we can eagerly get a ptr.
|
||||
|
||||
// Step 1: determine the length.
|
||||
let alloc = this.memory.get_raw(ptr.alloc_id)?;
|
||||
let mut len = Size::ZERO;
|
||||
loop {
|
||||
let byte = alloc.read_scalar(this, ptr.offset(len, this)?, size1)?.to_u8()?;
|
||||
if byte == 0 {
|
||||
break;
|
||||
} else {
|
||||
len = len + size1;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: get the bytes.
|
||||
this.memory.read_bytes(ptr.into(), len)
|
||||
}
|
||||
|
||||
fn read_wide_str(&self, sptr: Scalar<Tag>) -> InterpResult<'tcx, Vec<u16>> {
|
||||
let this = self.eval_context_ref();
|
||||
let size2 = Size::from_bytes(2);
|
||||
|
||||
let mut ptr = this.force_ptr(sptr)?; // We need to read at least 1 wchar, so we can eagerly get a ptr.
|
||||
let mut wchars = Vec::new();
|
||||
let alloc = this.memory.get_raw(ptr.alloc_id)?;
|
||||
loop {
|
||||
let wchar = alloc.read_scalar(this, ptr, size2)?.to_u16()?;
|
||||
if wchar == 0 {
|
||||
break;
|
||||
} else {
|
||||
wchars.push(wchar);
|
||||
ptr = ptr.offset(size2, this)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(wchars)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that the number of args is what we expect.
|
||||
|
@ -405,7 +405,7 @@ fn emulate_foreign_item_by_name(
|
||||
check_abi(abi, Abi::C { unwind: false })?;
|
||||
let &[ref ptr] = check_arg_count(args)?;
|
||||
let ptr = this.read_scalar(ptr)?.check_init()?;
|
||||
let n = this.memory.read_c_str(ptr)?.len();
|
||||
let n = this.read_c_str(ptr)?.len();
|
||||
this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||
|
||||
use rustc_target::abi::LayoutOf;
|
||||
use rustc_target::abi::{LayoutOf, Size};
|
||||
|
||||
use crate::*;
|
||||
|
||||
@ -50,19 +50,19 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi
|
||||
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
|
||||
/// Helper function to read an OsString from a null-terminated sequence of bytes, which is what
|
||||
/// the Unix APIs usually handle.
|
||||
fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar<Tag>) -> InterpResult<'tcx, &'a OsStr>
|
||||
fn read_os_str_from_c_str<'a>(&'a self, sptr: Scalar<Tag>) -> InterpResult<'tcx, &'a OsStr>
|
||||
where
|
||||
'tcx: 'a,
|
||||
'mir: 'a,
|
||||
{
|
||||
let this = self.eval_context_ref();
|
||||
let bytes = this.memory.read_c_str(scalar)?;
|
||||
let bytes = this.read_c_str(sptr)?;
|
||||
bytes_to_os_str(bytes)
|
||||
}
|
||||
|
||||
/// Helper function to read an OsString from a 0x0000-terminated sequence of u16,
|
||||
/// which is what the Windows APIs usually handle.
|
||||
fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar<Tag>) -> InterpResult<'tcx, OsString>
|
||||
fn read_os_str_from_wide_str<'a>(&'a self, sptr: Scalar<Tag>) -> InterpResult<'tcx, OsString>
|
||||
where
|
||||
'tcx: 'a,
|
||||
'mir: 'a,
|
||||
@ -78,7 +78,7 @@ pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec<u16>) -> InterpResult<'tcx, OsS
|
||||
Ok(s.into())
|
||||
}
|
||||
|
||||
let u16_vec = self.eval_context_ref().memory.read_wide_str(scalar)?;
|
||||
let u16_vec = self.eval_context_ref().read_wide_str(sptr)?;
|
||||
u16vec_to_osstring(u16_vec)
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec<u16>) -> InterpResult<'tcx, OsS
|
||||
fn write_os_str_to_c_str(
|
||||
&mut self,
|
||||
os_str: &OsStr,
|
||||
scalar: Scalar<Tag>,
|
||||
sptr: Scalar<Tag>,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
let bytes = os_str_to_bytes(os_str)?;
|
||||
@ -102,7 +102,7 @@ fn write_os_str_to_c_str(
|
||||
}
|
||||
self.eval_context_mut()
|
||||
.memory
|
||||
.write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?;
|
||||
.write_bytes(sptr, bytes.iter().copied().chain(iter::once(0u8)))?;
|
||||
Ok((true, string_length))
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ fn write_os_str_to_c_str(
|
||||
fn write_os_str_to_wide_str(
|
||||
&mut self,
|
||||
os_str: &OsStr,
|
||||
scalar: Scalar<Tag>,
|
||||
sptr: Scalar<Tag>,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
#[cfg(windows)]
|
||||
@ -136,15 +136,27 @@ fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec<u16>> {
|
||||
// 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 {
|
||||
let string_length = string_length.checked_add(1).unwrap();
|
||||
if size < string_length {
|
||||
return Ok((false, string_length));
|
||||
}
|
||||
|
||||
// Store the UTF-16 string.
|
||||
self.eval_context_mut()
|
||||
.memory
|
||||
.write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?;
|
||||
Ok((true, string_length))
|
||||
let size2 = Size::from_bytes(2);
|
||||
let this = self.eval_context_mut();
|
||||
let tcx = &*this.tcx;
|
||||
let ptr = this.force_ptr(sptr)?; // we need to write at least the 0 terminator
|
||||
let alloc = this.memory.get_raw_mut(ptr.alloc_id)?;
|
||||
for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() {
|
||||
let offset = u64::try_from(offset).unwrap();
|
||||
alloc.write_scalar(
|
||||
tcx,
|
||||
ptr.offset(size2 * offset, tcx)?,
|
||||
Scalar::from_u16(wchar).into(),
|
||||
size2,
|
||||
)?;
|
||||
}
|
||||
Ok((true, string_length - 1))
|
||||
}
|
||||
|
||||
/// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.
|
||||
@ -178,13 +190,13 @@ fn alloc_os_str_as_wide_str(
|
||||
}
|
||||
|
||||
/// Read a null-terminated sequence of bytes, and perform path separator conversion if needed.
|
||||
fn read_path_from_c_str<'a>(&'a self, scalar: Scalar<Tag>) -> InterpResult<'tcx, Cow<'a, Path>>
|
||||
fn read_path_from_c_str<'a>(&'a self, sptr: Scalar<Tag>) -> InterpResult<'tcx, Cow<'a, Path>>
|
||||
where
|
||||
'tcx: 'a,
|
||||
'mir: 'a,
|
||||
{
|
||||
let this = self.eval_context_ref();
|
||||
let os_str = this.read_os_str_from_c_str(scalar)?;
|
||||
let os_str = this.read_os_str_from_c_str(sptr)?;
|
||||
|
||||
Ok(match this.convert_path_separator(Cow::Borrowed(os_str), PathConversion::TargetToHost) {
|
||||
Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)),
|
||||
@ -193,9 +205,9 @@ fn read_path_from_c_str<'a>(&'a self, scalar: Scalar<Tag>) -> InterpResult<'tcx,
|
||||
}
|
||||
|
||||
/// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed.
|
||||
fn read_path_from_wide_str(&self, scalar: Scalar<Tag>) -> InterpResult<'tcx, PathBuf> {
|
||||
fn read_path_from_wide_str(&self, sptr: Scalar<Tag>) -> InterpResult<'tcx, PathBuf> {
|
||||
let this = self.eval_context_ref();
|
||||
let os_str = this.read_os_str_from_wide_str(scalar)?;
|
||||
let os_str = this.read_os_str_from_wide_str(sptr)?;
|
||||
|
||||
Ok(this
|
||||
.convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost)
|
||||
@ -208,13 +220,13 @@ fn read_path_from_wide_str(&self, scalar: Scalar<Tag>) -> InterpResult<'tcx, Pat
|
||||
fn write_path_to_c_str(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
scalar: Scalar<Tag>,
|
||||
sptr: Scalar<Tag>,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
let this = self.eval_context_mut();
|
||||
let os_str = this
|
||||
.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
|
||||
this.write_os_str_to_c_str(&os_str, scalar, size)
|
||||
this.write_os_str_to_c_str(&os_str, sptr, size)
|
||||
}
|
||||
|
||||
/// Write a Path to the machine memory (as a null-terminated sequence of `u16`s),
|
||||
@ -222,13 +234,13 @@ fn write_path_to_c_str(
|
||||
fn write_path_to_wide_str(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
scalar: Scalar<Tag>,
|
||||
sptr: Scalar<Tag>,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
let this = self.eval_context_mut();
|
||||
let os_str = this
|
||||
.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
|
||||
this.write_os_str_to_wide_str(&os_str, scalar, size)
|
||||
this.write_os_str_to_wide_str(&os_str, sptr, size)
|
||||
}
|
||||
|
||||
fn convert_path_separator<'a>(
|
||||
|
@ -187,7 +187,7 @@ fn emulate_foreign_item_by_name(
|
||||
let &[ref handle, ref symbol] = check_arg_count(args)?;
|
||||
this.read_scalar(handle)?.to_machine_usize(this)?;
|
||||
let symbol = this.read_scalar(symbol)?.check_init()?;
|
||||
let symbol_name = this.memory.read_c_str(symbol)?;
|
||||
let symbol_name = this.read_c_str(symbol)?;
|
||||
if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? {
|
||||
let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
|
||||
this.write_scalar(Scalar::from(ptr), dest)?;
|
||||
|
@ -111,7 +111,7 @@ fn prctl(
|
||||
let option = this.read_scalar(option)?.to_i32()?;
|
||||
if option == this.eval_libc_i32("PR_SET_NAME")? {
|
||||
let address = this.read_scalar(arg2)?.check_init()?;
|
||||
let mut name = this.memory.read_c_str(address)?.to_owned();
|
||||
let mut name = this.read_c_str(address)?.to_owned();
|
||||
// The name should be no more than 16 bytes, including the null
|
||||
// byte. Since `read_c_str` returns the string without the null
|
||||
// byte, we need to truncate to 15.
|
||||
@ -134,7 +134,7 @@ fn pthread_setname_np(&mut self, name: Scalar<Tag>) -> InterpResult<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
this.assert_target_os("macos", "pthread_setname_np");
|
||||
|
||||
let name = this.memory.read_c_str(name)?.to_owned();
|
||||
let name = this.read_c_str(name)?.to_owned();
|
||||
this.set_active_thread_name(name);
|
||||
|
||||
Ok(())
|
||||
|
@ -271,7 +271,7 @@ fn emulate_foreign_item_by_name(
|
||||
#[allow(non_snake_case)]
|
||||
let &[ref hModule, ref lpProcName] = check_arg_count(args)?;
|
||||
this.read_scalar(hModule)?.to_machine_isize(this)?;
|
||||
let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?;
|
||||
let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?;
|
||||
if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? {
|
||||
let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
|
||||
this.write_scalar(Scalar::from(ptr), dest)?;
|
||||
|
Loading…
Reference in New Issue
Block a user