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 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
Duration::new(seconds, nanoseconds)
|
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.
|
/// Check that the number of args is what we expect.
|
||||||
|
@ -405,7 +405,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
check_abi(abi, Abi::C { unwind: false })?;
|
check_abi(abi, Abi::C { unwind: false })?;
|
||||||
let &[ref ptr] = check_arg_count(args)?;
|
let &[ref ptr] = check_arg_count(args)?;
|
||||||
let ptr = this.read_scalar(ptr)?.check_init()?;
|
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)?;
|
this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt};
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||||
|
|
||||||
use rustc_target::abi::LayoutOf;
|
use rustc_target::abi::{LayoutOf, Size};
|
||||||
|
|
||||||
use crate::*;
|
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> {
|
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
|
/// Helper function to read an OsString from a null-terminated sequence of bytes, which is what
|
||||||
/// the Unix APIs usually handle.
|
/// 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
|
where
|
||||||
'tcx: 'a,
|
'tcx: 'a,
|
||||||
'mir: 'a,
|
'mir: 'a,
|
||||||
{
|
{
|
||||||
let this = self.eval_context_ref();
|
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)
|
bytes_to_os_str(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to read an OsString from a 0x0000-terminated sequence of u16,
|
/// Helper function to read an OsString from a 0x0000-terminated sequence of u16,
|
||||||
/// which is what the Windows APIs usually handle.
|
/// 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
|
where
|
||||||
'tcx: 'a,
|
'tcx: 'a,
|
||||||
'mir: 'a,
|
'mir: 'a,
|
||||||
@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
Ok(s.into())
|
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)
|
u16vec_to_osstring(u16_vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn write_os_str_to_c_str(
|
fn write_os_str_to_c_str(
|
||||||
&mut self,
|
&mut self,
|
||||||
os_str: &OsStr,
|
os_str: &OsStr,
|
||||||
scalar: Scalar<Tag>,
|
sptr: Scalar<Tag>,
|
||||||
size: u64,
|
size: u64,
|
||||||
) -> InterpResult<'tcx, (bool, u64)> {
|
) -> InterpResult<'tcx, (bool, u64)> {
|
||||||
let bytes = os_str_to_bytes(os_str)?;
|
let bytes = os_str_to_bytes(os_str)?;
|
||||||
@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
}
|
}
|
||||||
self.eval_context_mut()
|
self.eval_context_mut()
|
||||||
.memory
|
.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))
|
Ok((true, string_length))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn write_os_str_to_wide_str(
|
fn write_os_str_to_wide_str(
|
||||||
&mut self,
|
&mut self,
|
||||||
os_str: &OsStr,
|
os_str: &OsStr,
|
||||||
scalar: Scalar<Tag>,
|
sptr: Scalar<Tag>,
|
||||||
size: u64,
|
size: u64,
|
||||||
) -> InterpResult<'tcx, (bool, u64)> {
|
) -> InterpResult<'tcx, (bool, u64)> {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -136,15 +136,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required
|
// 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.
|
// 0x0000 terminator to memory would cause an out-of-bounds access.
|
||||||
let string_length = u64::try_from(u16_vec.len()).unwrap();
|
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));
|
return Ok((false, string_length));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the UTF-16 string.
|
// Store the UTF-16 string.
|
||||||
self.eval_context_mut()
|
let size2 = Size::from_bytes(2);
|
||||||
.memory
|
let this = self.eval_context_mut();
|
||||||
.write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?;
|
let tcx = &*this.tcx;
|
||||||
Ok((true, string_length))
|
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.
|
/// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes.
|
||||||
@ -178,13 +190,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read a null-terminated sequence of bytes, and perform path separator conversion if needed.
|
/// 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
|
where
|
||||||
'tcx: 'a,
|
'tcx: 'a,
|
||||||
'mir: 'a,
|
'mir: 'a,
|
||||||
{
|
{
|
||||||
let this = self.eval_context_ref();
|
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) {
|
Ok(match this.convert_path_separator(Cow::Borrowed(os_str), PathConversion::TargetToHost) {
|
||||||
Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)),
|
Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)),
|
||||||
@ -193,9 +205,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed.
|
/// 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 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
|
Ok(this
|
||||||
.convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost)
|
.convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost)
|
||||||
@ -208,13 +220,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn write_path_to_c_str(
|
fn write_path_to_c_str(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
scalar: Scalar<Tag>,
|
sptr: Scalar<Tag>,
|
||||||
size: u64,
|
size: u64,
|
||||||
) -> InterpResult<'tcx, (bool, u64)> {
|
) -> InterpResult<'tcx, (bool, u64)> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
let os_str = this
|
let os_str = this
|
||||||
.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
|
.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),
|
/// Write a Path to the machine memory (as a null-terminated sequence of `u16`s),
|
||||||
@ -222,13 +234,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
fn write_path_to_wide_str(
|
fn write_path_to_wide_str(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
scalar: Scalar<Tag>,
|
sptr: Scalar<Tag>,
|
||||||
size: u64,
|
size: u64,
|
||||||
) -> InterpResult<'tcx, (bool, u64)> {
|
) -> InterpResult<'tcx, (bool, u64)> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
let os_str = this
|
let os_str = this
|
||||||
.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
|
.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>(
|
fn convert_path_separator<'a>(
|
||||||
|
@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
let &[ref handle, ref symbol] = check_arg_count(args)?;
|
let &[ref handle, ref symbol] = check_arg_count(args)?;
|
||||||
this.read_scalar(handle)?.to_machine_usize(this)?;
|
this.read_scalar(handle)?.to_machine_usize(this)?;
|
||||||
let symbol = this.read_scalar(symbol)?.check_init()?;
|
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)? {
|
if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? {
|
||||||
let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
|
let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
|
||||||
this.write_scalar(Scalar::from(ptr), dest)?;
|
this.write_scalar(Scalar::from(ptr), dest)?;
|
||||||
|
@ -111,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
let option = this.read_scalar(option)?.to_i32()?;
|
let option = this.read_scalar(option)?.to_i32()?;
|
||||||
if option == this.eval_libc_i32("PR_SET_NAME")? {
|
if option == this.eval_libc_i32("PR_SET_NAME")? {
|
||||||
let address = this.read_scalar(arg2)?.check_init()?;
|
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
|
// The name should be no more than 16 bytes, including the null
|
||||||
// byte. Since `read_c_str` returns the string without the null
|
// byte. Since `read_c_str` returns the string without the null
|
||||||
// byte, we need to truncate to 15.
|
// byte, we need to truncate to 15.
|
||||||
@ -134,7 +134,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
this.assert_target_os("macos", "pthread_setname_np");
|
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);
|
this.set_active_thread_name(name);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -271,7 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
let &[ref hModule, ref lpProcName] = check_arg_count(args)?;
|
let &[ref hModule, ref lpProcName] = check_arg_count(args)?;
|
||||||
this.read_scalar(hModule)?.to_machine_isize(this)?;
|
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)? {
|
if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? {
|
||||||
let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
|
let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym));
|
||||||
this.write_scalar(Scalar::from(ptr), dest)?;
|
this.write_scalar(Scalar::from(ptr), dest)?;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user