Description
Good day folks,
I hit a ICE today. I installed nightly today (and it's reporting 1.81) so I think it's up to date.
This might be related to #2904, but it's not a no_std crate. I see a shim for wcslen in https://github.com/rust-lang/miri/blob/dc286ac1432932b2a710789de40ae8bc4e7ea7c1/src/shims/foreign_items.rs - but it looks like that shim doesn't work for msvc windows targets at a minimum.
But I'm not an expert on Miri.
windows_core::PCWSTR and windows_core::PWSTR both trivially trigger in via their .len() method - meaning a lot of windows code could benefit.
Edit: repro has been minimized further, see #3692 (comment)
// windows-core 0.57.0 is the original source of the struct involved
// I've minimized the example (Trimming unnecessary derive macros, unused functions, et cetera)
// As best I can.
// https://github.com/microsoft/windows-rs/commit/15947886be041bebd0fe670fd4e73f18d95100d0
/// A pointer to a constant null-terminated string of 16-bit Unicode characters.
#[repr(transparent)]
pub struct PCWSTR(pub *const u16);
impl PCWSTR {
/// Construct a new `PCWSTR` from a raw pointer
pub const fn from_raw(ptr: *const u16) -> Self {
Self(ptr)
}
/// String length without the trailing 0
///
/// # Safety
///
/// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
pub unsafe fn len(&self) -> usize {
//#[cfg(windows)]
// It's specifically the inclusion of this that makes or breaks the repro
// The other non-windows one does not trigger the ICE.
let len = {
extern "C" {
fn wcslen(s: *const u16) -> usize;
}
wcslen(self.0)
};
// #[cfg(not(windows))]
// let len = {
// let mut len = 0;
// let mut ptr = self.0;
// while ptr.read() != 0 {
// len += 1;
// ptr = ptr.add(1);
// }
// len
// };
len
}
}
pub fn does_not_trigger_ice_without_proc_macro()
{
// This isn't the most portable from endianness perspective. But it'll do.
let my_str: [u16; 2] = ['a' as u16 , 0];
let my_pcwstr = PCWSTR::from_raw(my_str.as_ptr());
// SAFETY: doesn't matter if it's safe, point is that this doesn't trigger an ICE.
let _my_ice_trigger = unsafe { my_pcwstr.len() };
}
#[cfg(test)]
mod tests
{
use crate::{does_not_trigger_ice_without_proc_macro, PCWSTR};
// /// This works as well to trigger it.
// #[test]
// pub fn cause_ice2()
// {
// does_not_trigger_ice_without_proc_macro()
// }
#[test]
pub fn cause_ice()
{
// This isn't the most portable from endianness perspective. But it'll do.
let my_str: [u16; 2] = ['a' as u16 , 0];
let my_pcwstr = PCWSTR::from_raw(my_str.as_ptr());
// SAFETY: doesn't matter if it's safe, point is that this doesn't trigger an ICE.
let _my_ice_trigger = unsafe { my_pcwstr.len() };
}
}
It also triggers on PWSTR. I don't think it repros on strlen though - which makes sense with the backtrace.
wcslen is utf16, not utf32, on Windows.