You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi
When testing the windows_strings::h!() macro with miri it flags undefined behavior when calling deref() on the &HSTRING (ie getting the &[u16] from the &HSTRING).
error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 32 bytes of memory, but got alloc101 which is only 24 bytes from the end of the allocation
--> /home/ru/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mut_ptr.rs:288:57
|
288 | if self.is_null() { None } else { unsafe { Some(&*self) } }
| ^^^^^^ out-of-bounds pointer use: expected a pointer to 32 bytes of memory, but got alloc101 which is only 24 bytes from the end of the allocation
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: BACKTRACE:
= note: inside `std::ptr::mut_ptr::<impl *mut windows_strings::hstring_header::HStringHeader>::as_ref::<'_>` at /home/ru/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mut_ptr.rs:288:57: 288:63
= note: inside `windows_strings::HSTRING::as_header` at /home/ru/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows-strings-0.3.1/src/hstring.rs:61:18: 61:33
= note: inside `<windows_strings::HSTRING as std::ops::Deref>::deref` at /home/ru/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/windows-strings-0.3.1/src/hstring.rs:69:31: 69:47
note: inside `main`
--> src/main.rs:3:28
|
3 | let my_slice: &[u16] = &my_hstr;
| ^^^^^^^^
I believe this is due to the fact the h!() macro uses a different HSTRING_HEADER struct to the expected HStringHeader. The difference in these structs is appears to be because the macro does not partake in reference counting, it omits the latter reference counting fields and sets a flag to indicate that.
This means when HSTRING::as_header is called it converts the inner pointer to a reference. I believe this is undefined behavior because the reference does not point to a full HStringHeader.
I will note that this is a private method and private type, all the users of this method correctly check the flags before accessing the fields that may or may not be present, so as far as I can tell there is no way to use this incorrectly in a program.
My suggestion would be to change the HSTRING_HEADER struct to include the missing fields. To avoid exposing RefCount we can use i32.
#[doc(hidden)]#[repr(C)]pubstructHSTRING_HEADER{pubflags:u32,publen:u32,pubpadding1:u32,pubpadding2:u32,pubptr:*constu16,// unused because refcounting is disabled for hstring literalspubcount:i32,pubbuffer_start:u16,}
From my testing this change fixes the issue and miri no longer flags undefined behaviour. I'm happy to create a pull request for this.
I took a quick look and sure enough it repros as follows:
cargo miri test -p test_strings --test literals
The fix seems reasonable but I'd like to get some miri testing as part of the build if we're going to fix stuff like this. So I'll go ahead and open a PR with a new workflow to cover this and you can take a look and let me know what you think.
Summary
Hi
When testing the
windows_strings::h!()
macro with miri it flags undefined behavior when callingderef()
on the&HSTRING
(ie getting the&[u16]
from the&HSTRING
).Miri outputs this
I believe this is due to the fact the
h!()
macro uses a differentHSTRING_HEADER
struct to the expectedHStringHeader
. The difference in these structs is appears to be because the macro does not partake in reference counting, it omits the latter reference counting fields and sets a flag to indicate that.This means when
HSTRING::as_header
is called it converts the inner pointer to a reference. I believe this is undefined behavior because the reference does not point to a fullHStringHeader
.I will note that this is a private method and private type, all the users of this method correctly check the flags before accessing the fields that may or may not be present, so as far as I can tell there is no way to use this incorrectly in a program.
My suggestion would be to change the
HSTRING_HEADER
struct to include the missing fields. To avoid exposing RefCount we can use i32.From my testing this change fixes the issue and miri no longer flags undefined behaviour. I'm happy to create a pull request for this.
Kind regards,
Ruairidh
Crate manifest
Crate code
The text was updated successfully, but these errors were encountered: