commit
3d269e9633
3 changed files with 64 additions and 9 deletions
|
|
@ -982,29 +982,46 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
Ok((true, string_length))
|
||||
}
|
||||
|
||||
/// Read a sequence of u16 until the first null terminator.
|
||||
fn read_wide_str(&self, mut ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u16>> {
|
||||
/// Helper function to read a sequence of unsigned integers of the given size and alignment
|
||||
/// until the first null terminator.
|
||||
fn read_c_str_with_char_size<T>(
|
||||
&self,
|
||||
mut ptr: Pointer<Option<Provenance>>,
|
||||
size: Size,
|
||||
align: Align,
|
||||
) -> InterpResult<'tcx, Vec<T>>
|
||||
where
|
||||
T: TryFrom<u128>,
|
||||
<T as TryFrom<u128>>::Error: std::fmt::Debug,
|
||||
{
|
||||
assert_ne!(size, Size::ZERO);
|
||||
|
||||
let this = self.eval_context_ref();
|
||||
let size2 = Size::from_bytes(2);
|
||||
this.check_ptr_align(ptr, Align::from_bytes(2).unwrap())?;
|
||||
|
||||
this.check_ptr_align(ptr, align)?;
|
||||
|
||||
let mut wchars = Vec::new();
|
||||
loop {
|
||||
// FIXME: We are re-getting the allocation each time around the loop.
|
||||
// Would be nice if we could somehow "extend" an existing AllocRange.
|
||||
let alloc = this.get_ptr_alloc(ptr, size2)?.unwrap(); // not a ZST, so we will get a result
|
||||
let wchar = alloc.read_integer(alloc_range(Size::ZERO, size2))?.to_u16()?;
|
||||
if wchar == 0 {
|
||||
let alloc = this.get_ptr_alloc(ptr, size)?.unwrap(); // not a ZST, so we will get a result
|
||||
let wchar_int = alloc.read_integer(alloc_range(Size::ZERO, size))?.to_bits(size)?;
|
||||
if wchar_int == 0 {
|
||||
break;
|
||||
} else {
|
||||
wchars.push(wchar);
|
||||
ptr = ptr.offset(size2, this)?;
|
||||
wchars.push(wchar_int.try_into().unwrap());
|
||||
ptr = ptr.offset(size, this)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(wchars)
|
||||
}
|
||||
|
||||
/// Read a sequence of u16 until the first null terminator.
|
||||
fn read_wide_str(&self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u16>> {
|
||||
self.read_c_str_with_char_size(ptr, Size::from_bytes(2), Align::from_bytes(2).unwrap())
|
||||
}
|
||||
|
||||
/// Helper function to write a sequence of u16 with an added 0x0000-terminator, which is what
|
||||
/// 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
|
||||
|
|
@ -1037,6 +1054,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
Ok((true, string_length))
|
||||
}
|
||||
|
||||
/// Read a sequence of wchar_t until the first null terminator.
|
||||
/// Always returns a `Vec<u32>` no matter the size of `wchar_t`.
|
||||
fn read_wchar_t_str(&self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u32>> {
|
||||
let this = self.eval_context_ref();
|
||||
let wchar_t = this.libc_ty_layout("wchar_t");
|
||||
self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi)
|
||||
}
|
||||
|
||||
/// Check that the ABI is what we expect.
|
||||
fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
|
||||
if abi != exp_abi {
|
||||
|
|
|
|||
|
|
@ -657,6 +657,16 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
dest,
|
||||
)?;
|
||||
}
|
||||
"wcslen" => {
|
||||
let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let ptr = this.read_pointer(ptr)?;
|
||||
// This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
|
||||
let n = this.read_wchar_t_str(ptr)?.len();
|
||||
this.write_scalar(
|
||||
Scalar::from_target_usize(u64::try_from(n).unwrap(), this),
|
||||
dest,
|
||||
)?;
|
||||
}
|
||||
"memcpy" => {
|
||||
let [ptr_dest, ptr_src, n] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
|
|
|
|||
20
src/tools/miri/tests/pass-dep/wcslen.rs
Normal file
20
src/tools/miri/tests/pass-dep/wcslen.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
fn to_c_wchar_t_str(s: &str) -> Vec<libc::wchar_t> {
|
||||
let mut r = Vec::<libc::wchar_t>::new();
|
||||
for c in s.bytes() {
|
||||
if c == 0 {
|
||||
panic!("can't contain a null character");
|
||||
}
|
||||
if c >= 128 {
|
||||
panic!("only ASCII supported");
|
||||
}
|
||||
r.push(c.into());
|
||||
}
|
||||
r.push(0);
|
||||
r
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let s = to_c_wchar_t_str("Rust");
|
||||
let len = unsafe { libc::wcslen(s.as_ptr()) };
|
||||
assert_eq!(len, 4);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue